Given the following,
1.class X2{
2. public X2 x;
3. public static void main(String[] args){
4. X2 x2=new X2();
5. X2 x3=new X2();
6. x2.x=x3;
7. x3.x=x2;
8. x2=new X2();
9. x3=x2;
10. doComplexStuff();
11.}
12.}
after line 9 runs,how many objects are eligible for garbage collection?
A.0 B.1 C.2 D.3 E.4请概念清楚者给出详细的解释,谢谢~~~
1.class X2{
2. public X2 x;
3. public static void main(String[] args){
4. X2 x2=new X2();
5. X2 x3=new X2();
6. x2.x=x3;
7. x3.x=x2;
8. x2=new X2();
9. x3=x2;
10. doComplexStuff();
11.}
12.}
after line 9 runs,how many objects are eligible for garbage collection?
A.0 B.1 C.2 D.3 E.4请概念清楚者给出详细的解释,谢谢~~~
解决方案 »
- 求教:点击button产生第二个窗口,里面也是一个按钮,我想实现点击这个按钮后,第二个窗口消失,但第一个button所在的窗口不会消失。请问该怎么写。
- no jvm could be found on your system.please define EXE1J_JAVA_HOME to point
- 请推荐基本学习java的书
- 新手求助
- 关于JTextPane的光标问题
- J2SE经典学习视频下载地址
- java socket和c通信时丢失数据是什么原因?
- 一个jdbc巨郁闷的问题
- 请问哪里有AIX5.1下的j2sdk开发包下载
- 哪位大虾能够帮我这个JTable的小问题阿!!!
- 怎样获取MP4格式文件的时长与码率,各位帮帮忙哈,给点思路或给个网子或什么的都给分哈谢谢了!!!………………
- 制作学籍管理系统
9. x3=x2;
这时只有第8行的这个new X2对象被引用,所以不被回收,其余的第4,5 行的对象new X2()没有被引用所以被垃圾回收,所以我认为是2个。
4. X2 x2=new X2();
5. X2 x3=new X2();
可以回收,而9. x3=x2;则是
x3、x2共同指向8.x2=new X2();创建的对象。所以是2。
晕。
根据ref来判断回收的话,前两个X2对象是相互引用的,答案是0.
但这样肯定是会造成内存泄漏的,所以现实中JVM都应该采用孤岛回收的策略.2,认同.
public GcTest g;
public static void main(String[] args) {
GcTest x2 = new GcTest();
GcTest x3 = new GcTest();
x2.g = x3;
x3.g = x2;
x2 = new GcTest();
x3=x2;
System.gc();
}
@Override
protected void finalize() throws Throwable {
System.out.println("clear");
}}测试了一下,输出2次clear
既然有2个人说3,就想听听为什么。测试的代码,上面 simbas00给了。To sussman:我的详细的解释。
这个题糊弄人的地方,在
2. public X2 x;
因此,要清楚引用变量(或者叫句柄)和对象是不同的两个东西。句柄将持有对象的ref,它不是对象。有几个句柄?4个,x2、x3、x2.x和x3.x,程序中有几个对象?数new出现的次数(Class的那个方法这里不考虑)。3个。垃圾对象是引用全部失效的对象,
6. x2.x=x3;
7. x3.x=x2;
说明,对象1#和2#的引用曾经被x3.x和x2.x持有,当8. x2=new X2();
9. x3=x2;
8后,x2.x为null,9之后,x3.x为null。因此
对象1#和2#成为垃圾。
而对象3#有句柄x2和x3持有。
-----
我不这样认为,8后,x2.x不为null
晕,上面说了啊。
“x2指向的对象是新对象啊,其成员变量x仅仅被默认初始化,当然是null了”
public GcTest g;
public static void main(String[] args) {
GcTest x2 = new GcTest();
GcTest x3 = new GcTest();
x2.g = x3;
x3.g = x2;
对象的成员变量分配在heap上,你有根据吗?
这是Java内存管理最基本的规定。对象的内存在heap分配,就是说的是对象的所有成员变量在heap分配空间啊。x2也分配在heap上?
no,局部变量全部在stack中分配空间。
public GcTest g;
public static void main(String[] args) {
GcTest x2 = new GcTest();
GcTest x3 = new GcTest();
x2.g = x3;
x3.g = x2;
”
public GcTest g;
g是成员,x2不是,
public class A {
public A g;
public static void main(String[] args) {
A x2 = new A();
System.out.println(x2.g); A x3 = new A();
x2.g = x3;System.out.println(x2.g);
x3.g = x2;
x2 = new A();System.out.println(x2.g);
x3=x2;
System.gc();
}
@Override
protected void finalize() throws Throwable {
System.out.println("clear");
}}null
A@11b86e7
null
clear
clear
public GcTest g;
public static void main(String[] args) {GcTest x2 = new GcTest();
GcTest x3 = new GcTest();
x2.g = x3;
System.out.println(x2);x3.g = x2;
x2 = new GcTest();
x3=x2;
System.gc();
System.out.println(x2); }
protected void finalize() throws Throwable {
System.out.println("clear");
}}
2. public X2 x;//这个是X2的成员变量,内存组织描述在field_info里,
3. public static void main(String[] args){//主方法
4. X2 x2=new X2();//x2是X2的局部变量,分配在栈上,只是一个ref,他指向一个在heap上分配的内存new X2();,这个好象是16K,这个new X2();中的x的成员变量是和这个对象的生命周期是一样的.因为我还再查关于成员变量堆内存的组织形式.
5. X2 x3=new X2();//x3同x2
6. x2.x=x3;//这里用x2的x成员变量指向了x3也同时指向的 在heap上分配的new X2();
7. x3.x=x2;//这里用x3的x成员变量指向了x2也同时指向的 在heap上分配的new X2();
8. x2=new X2();//这里x2在栈中新指向了另一个new X2();而原来的她所指向的那个对象只有x3的x作为她的ref,到这里我认为还没有任何的垃圾.
9. x3=x2;//这步才是产生垃圾最重要的那部分,因为x3指向了新的对象,也就是说没有任何栈上的指针指向最初分配的那两个对象了.就相当于两个内存的heap上的内存块互相指着.
而这种没有栈指针依赖的对象是无法存活的.
例如你直接写这样的代码:new X2();就会利马变成垃圾.
所以在这一步同时出现了两个垃圾对象,也就是最初的两个new X2();
10.
11.}
12.}
结论: 答案是两个我希望你能楼主和大家,当然还有yqj2065(严千钧)看一下,第8行,因为我认为这里并不产生垃圾这是我对这个帖子的半完整解释.遗留的问题:成员变量在heap上的组织形式.谢谢各位观看.
再说是不是应该出了"}"外,垃圾回收机制才会生效呢?我觉得关键是要弄清楚垃圾回收机制是在什么时候被调用的?
上面的各位都是在自己的代码中强制调用System.gc()才的得到结论。
欢迎有JAVA#JSP兴趣的加入技术群:15328132
(为了不让无关人员加入,请回答一个JAVA的简单问题久可以接受高手们的指点!)
1.class X2{
2. public X2 x;
3. public static void main(String[] args){
4. X2 x2=new X2();
5. X2 x3=new X2();
6. x2.x=x3;
7. x3.x=x2;
8. x2=new X2();
9. x3=x2;
10. doComplexStuff();
11.}
12.}
after line 9 runs,how many objects are eligible for garbage collection?
A.0 B.1 C.2 D.3 E.4--
运行到line 5时,共创建了 2 个实例,并且交叉赋值给 x2, x2.x, x3, x3.x
这没有什么特别的,概括地讲也就是说:
x2,x3分别持有一个实例,同时根据成员变量x可以访问另外一个。--
运行到line 8时,情况发生了变化,x2指向一个新的实例(x2.x自然而然也就null了)
此时
x2持有第 3 个实例,但 x2.x = null (并不指向任何实例)
由于 x3 及 x3.x 仍然持有前面创建的 2 个实例,所以目前还没有对象被释放。--
运行到line 9时,x3也指向新的实例(和x2引用同一个实例)
此时
x3原来持有的实例被释放
能够通过 x3.x 访问的实例也被释放--
用符号ABC表示实例就是从x2 -> A
x2.x -> B
x3 -> B
x3.x -> A最终演变为x2 -> C
x2.x is null
x3 -> C
x3.x is null至此 A 和 B 将被 gc
上面大家分析的已经很不错了,我只是想说说上面的finalize的测试方法为什么是错误的?!我们知道gc是个不确定的行为,我们无法控制,JVM回收垃圾一直都是不可控的。
我认为这个题目出的比较好,如果这个代码
public class GcTest {
public GcTest g;
public static void main(String[] args) {
GcTest x2 = new GcTest();
GcTest x3 = new GcTest();
x2.g = x3;
x3.g = x2;
x2 = new GcTest();
x3=x2;
System.gc();
}
@Override
protected void finalize() throws Throwable {
System.out.println("clear");
}}
输出多少次clear我觉得都是没有问题的,(当然不会超过3次,因为一共就创建了3个对象)。这个代码和题目是不一样的。
题目中line9之后还有line10,这个是非常重要的,也就是说line9之后这个方法的作用域还没有结束,这时候符合垃圾回收的对象应该是
1。null
2。没有被引用的对象
而line10之后,就会有“结束作用域的局部对象”也符合垃圾回收的条件。
上面的finalize的测试就是犯了这个错误,实际上你这里按照题目的问题应该是3个对象,因为按照上面3条原则,创建的3个对象都是局部的,所以结束了函数作用域一定都符合垃圾回收的条件。之所有只输出了2次clear是因为gc是不确定的,这里gc了2个对象而已,但是符合垃圾回收的对象是3个!
正确与错误的解释。“finalize测试是不对的”“gc是个不确定的行为,我们无法控制,JVM回收垃圾一直都是不可控的”,理论上是正确。使用finalize的测试方法 ,常常忽略了“可回收”与“被回收”的差别。“题目中line9之后还有line10,这个是非常重要的,也就是说line9之后这个方法的作用域还没有结束”,
“而line10之后,就会有“结束作用域的局部对象”也符合垃圾回收的条件。”
“创建的3个对象都是局部的”
错误的或者说混乱的解释。一个基本的观点:对象没有/不受词法作用域的限制,受词法作用域限制的是引用变量(或者叫句柄)。作用域结束后,句柄被清除,可能由于对象ref的最后一个持有者丧失而导致对象沦为垃圾。
不要混淆对象与句柄。
如果能够让对象方便的受词法作用域限制,Java中的对象就不需要在heap中分配内存了。按照题目的问题,9后,垃圾对象是两个,当然此时使用finalize测试也是两个。
liu_you(滴水藏海) 摘录的"Heap, where objects are kept"但是,不同的JVM如何实现是另外一回事.有文章介绍,有的JVM甚至可以在物理的寄存器中给对象分配内存.我们仍然把这时的物理的寄存器视为heap.
public A g;
public static void main(String[] args) {
A x2 = new A();
A x3 = new A();
x2.g = x3;
x3.g = x2;
x2 = new A();
x3=x2;
while(true)
{
System.gc();
}
}
@Override
protected void finalize() throws Throwable {
System.out.println("clear");
}}
"我所要找的,就是要把,堆内存分配的结构和组织形式找到"
呵呵,有出息的家伙
希望 yqj2065(严千钧) 大哥能来这里踩一脚,我已没办法给分了
指教不敢,偶水平有限得很.
这题考的是java的垃圾回收、对象生成的机制
这就要说到堆内存和栈内存
2. public X2 x;
3. public static void main(String[] args){
4. X2 x2=new X2(); //产生新对象放到堆中。对象A1
5. X2 x3=new X2(); //产生新对象放到堆中。对象A2
6. x2.x=x3; //现在对象A2的句柄为:x2.x ,x3 两个
7. x3.x=x2; //现在对象A1的句柄为:x3.x ,x2 两个
8. x2=new X2(); //产生新对象放到堆中。对象A3 。句柄为 x2 同时对象A1丢失一个句柄x2 现在A1还有句柄x3.x
9. x3=x2; //A2丢失句柄 x3 目前A2还有句柄 x2.x。到次为止每个对象都有句屏,不会被当做垃圾回收。
10. doComplexStuff();
11.}
12.}
该paper探讨了JVM,.NET虚拟机的原理
总共产生了3个对象。
运行到9行时,对前两个对象的引用都不存在了,所以会被回收。而第三个的引用数量是2 ,显然不会被回收线程处理掉
所以应该是两个
因为一共new了3个.
在9 行后
x2,x3都指向了同一个对象.x2.xt x3.x都是NullPoint
其它两个没人引用了小弟是做C++的 只会一点Java
错了大家见凉!
最后x2,x3都指向了第三个创建的,所以第一,二个创建的已经没有指向他们的引用了,所以称为了垃圾
以前有那种非常简单的垃圾收集算法。就是检查对象上还有多少引用,如果为0,则回收。本题
如果按这种经典的算法,结果是:0个对象被回收。
但是,在现代的jvm中,垃圾收集算法主要是:从运行栈上开始,往下找,凡是能够被引用到的
对象才是活对象,不能被回收,否则,被回收。
1.class MockObject{
2. public MockObject x;
3. public static void main(String[] args){
4. MockObject x2=new MockObject();
5. MockObject x3=new MockObject();
6. x2.x=x3;
7. x3.x=x2;
8. x2=new MockObject();
9. x3=x2;
10. doComplexStuff();
11.}
12.}
首先要改一下类名,不能X2,否则太迷惑人。第八行彻底丢弃了原来申明的x2和x3。还有就是关于垃圾回收,虽然java规范说不能保证立即回收,但如果用java profiler查看一个java程序的运行状态的话,可以发现,垃圾回收实际上是非常频繁的,没几十毫秒就要做一次。
在java中你不必想c++中一样显示的释放你在堆中申请的空间(new),垃圾回收器可以帮你在背后自动释放你不需要的空间----一个类实例(对象)所占的空间.当一个对象不被引用时候满足被垃圾回收器回收的条件.注意,垃圾回收器是在一定条件下才启动.他可能随时启动,也可能在程序运行期间永远不启动.根据上述在执行第9行之后,堆中的每个对想都被引用,所以,答案是0.
5. X2 x3=new X2();这两个被回收了~~~
我是这么认为的~~====CSDN 小助手 V2.0 2005年10月16日发布====
CSDN小助手是一款脱离浏览器也可以访问Csdn论坛的软件
界面:http://blog.csdn.net/Qqwwee_Com/archive/2005/10/16/504620.aspx
下载:http://szlawbook.com/csdnv2/csdnv2.rar为神六喝彩,向所有科技工作者致敬!
拒绝日货。
从stack或static storage出发,走访所有references之后,便能找到所有存在对象,针对你所找到的references,你都必须再钻进它所代表(指向)的对象,然后循着该对象内含的所有references,再钻入他们所指对象,如此反复进行,直到访遍根源于stack或static storage上的references所形成的整个网络为止。你所走访的每个对象都必须是存活的。。根据以上说明,,其他对象就是符合垃圾回收条件的。另java从heap空间分配所有对象,所以对象references存在于堆中。故该题答案为2。
意思是指对象中的成员references存在于堆中
我也认为是2个,共穿创建了3 个对象,最后只存在一个了,2个对象为NULL。
不过我同意楼上大哥说的,我对finalize不是蛮信任。要它去回收垃圾是不能由我们控制的,它是自动调用的(在你的内存不够时)。
不过还是谢谢前辈指导,受益不少,谢谢
大多数的朋友都支持2个的答案。但我还是有点糊涂,请大家再指教一下。
第4、5行new了两个对象;
第6、7行对象的成员交叉引用了这两个对象;
第8行又new了一个新的对象,给了局部变量x2,但是原来分配给x2的空间应该并没有立即释放吧。
第9行又把x2对象赋值给x3,这时原来分配给x3的空间也没有释放。
第9行结束以后,就应该存在4个X2的对象,只是有两个已经不能访问了。
那么回收站中应该回收4给对象好像才合理。
大多数的朋友都支持2个的答案。但我还是有点糊涂,请大家再指教一下。
第4、5行new了两个对象;
第6、7行对象的成员交叉引用了这两个对象;
第8行又new了一个新的对象,给了局部变量x2,但是原来分配给x2的空间应该并没有立即释放吧。
第9行又把x2对象赋值给x3,这时原来分配给x3的空间也没有释放。
第9行结束以后,就应该存在4个X2的对象,只是有两个已经不能访问了。
那么回收站中应该回收4给对象好像才合理。
在第9行之后执行System.gc(),打印hash码x2,x3,x2.x,x3.x;
这四个应用,x2与x3应用同一个对象,x2.x和x3.x为空,说名这个两个对象被回收.
init :x3=X2@757aef
bt :x2=X2@35ce36
bt :x3=X2@757aef
ag :x2=X2@d9f9c3
end: x2=X2@d9f9c3
end: x3=X2@d9f9c3
public GcTest g;
public static void main(String[] args) {GcTest x2 = new GcTest();
GcTest x3 = new GcTest();
x2.g = x3;
System.out.println(x2);x3.g = x2;
x2 = new GcTest();
x3=x2;
x2=null;
x3=null;
System.gc();
System.out.println(x2);}
protected void finalize() throws Throwable {
System.out.println("clear");
}}
2. public X2 x;
3. public static void main(String[] args){
4. X2 x2=new X2();
5. X2 x3=new X2();
6. x2.x=x3;
7. x3.x=x2;
8. x2=new X2();
9. x3=x2;
10. doComplexStuff();
11.}
12.}
按我的理解也是两个
第4,5行:创建了两个对象,所以在stack上有两个ref:x2,x3。但CLASS:X2本身就有一个成员x,它也是X2的实例,所以在heap上实际有2个X2对象的空间产生,分别给x2,x3引用(为了方便后面解说,我叫它们为:OBJ1,OBJ2),x2.x和x3.x指向了NULL。
第6行:x2.x指向了x3(OBJ2)
第7行:x3.x指向了x2(OBJ1)
到这里,OBJ1被x2,x3.x同时引用,OBJ2被x2.x,x3同时引用
第8行:x2又指向了一个新的X2对象,此时heap又多了1个X2对象(到此一共3个,将这个新的对象叫为OBJ3)。它里面的x成员也是指向了null.
到这里:OBJ1被x3.x引用,OBJ2被x3引用,OBJ3被x2引用,x2.x指向了null。
第9行:x3指向了x2的引用对象:OBJ3。到这里就很明显了。x3指向OBJ3,x3.x指向了null(和x2的引用一样),那OBJ1和OBJ2都没被引用到,那它们就是GC的目标了。理解不知道是否有误,还请高手指点。
我是这样理解的,stack上放的是一些基础类型变量或者你调用方法时,也会在这里分配空间,在它的作用域结束时,它的空间也就被释放。而在heap上放的都一些对象(或者说是继续自Object的类对象),它们只有在没引用时才会可能被释放空间。还有上面的那些测试代码并不能说明什么问题,因为你的对象即使没有引用也不一定会被释放,测试的结果也有可能是1,也有可能是0。只有当你虚拟内存不够时,GC才会启动,但它也不是全部都释放,它会先释放一部分,到最如果内存还不够时,它才会检查所有对象进行释放,但这样就会影响到效率(时间较长)。
中说我是Terminator,还是再讨论讨论。首先的一点,我们不要过于担心GC何时释放垃圾,因为这不是我们能够决定的。一般从程序员的角度看,知道什么对象“可回收”就足够了。至于是否“被回收”的确很复杂。上面一些朋友已经提到了垃圾回收模型,引用记数模型因为存在循环引用问题,绝大多数GC已经放弃了它。但一个程序员判断垃圾的标准,还是“引用全部失效”。
wingjimmy(不死鸟) 摘录的《Think in java》中文版(第二版 候捷译)216页有这么一段话,告诉我们如何看待“引用全部失效”。
这个方法在什么时候被调用?当对象被GC判断为不可达的而要被回收时。就是说,我们不管finalize()实际完成了什么,它提供了一条信息,“这个对象是垃圾”。
大家可以这样测试:
protected void finalize() throws Throwable {
System.out.println("真正释放内存?管它呢,"+ this + "是垃圾" );
}如果该对象已经被回收,则finalize()已经被调用,在我们的测试代码中,这种情况不存在。
public A g;
public static void main(String[] args) {
System.out.println("1");
A x2 = new A();
System.out.println(x2);
A x3 = new A();
System.out.println(x3);
x2.g = x3;
System.out.println(x2.g);
x3.g = x2;
System.out.println(x3.g);
////////////////////////////////
System.out.println("2");
x2 = new A();
System.out.println(x2);
System.out.println(x3);
System.out.println(x2.g);
System.out.println(x3.g);
System.gc(); //********* System.out.println("3");
x3=x2;
System.out.println(x2);
System.out.println(x3);
System.out.println(x2.g);
System.out.println(x3.g);
System.gc(); /*System.out.println("4");
x2= new A();
System.out.println(x2);
System.out.println(x2.g);
System.gc();*/
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("真正释放内存?管它呢,"+ this + "是垃圾" );
}
}1
A@11b86e7
A@35ce36
A@35ce36
A@11b86e7
2
A@757aef
A@35ce36
null
A@11b86e7
3
A@757aef
A@757aef
null
null
真正释放内存?管它呢,A@35ce36是垃圾
真正释放内存?管它呢,A@11b86e7是垃圾
请按任意键继续. . .
public static void main(String[] args){
4. X2 x2=new X2();
5. X2 x3=new X2();
6. x2.x=x3;
7. x3.x=x2;
8. x2=new X2();
9. x3=x2;
10. doComplexStuff();
11.}前面new了两个:X2 x2=new X2(); X2 x3=new X2(); 之后又把x2new了一次,x2=new X2()。说到底,还是x2和x3两个。其他的要么回收了,要么只是做了指针变量而已。
不要被其他的东西迷惑了!~~~~~~~~~~~:)