一道外企软件公司笔试题,求详细解释~~~~

时间:2021-07-15 14:43:33
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

请概念清楚者给出详细的解释,谢谢~~~

112 个解决方案

#1


3

#2


有没有人能解释一下啊?我是真的不懂

#3


我也学习一下,我也感觉是 3 个,但我测试的结果好象是 2 个。比较奇怪。

#4


8.         x2=new X2();
9.         x3=x2;
这时只有第8行的这个new X2对象被引用,所以不被回收,其余的第4,5 行的对象new X2()没有被引用所以被垃圾回收,所以我认为是2个。

#5


java里并不是以ref的判断来决定gc的

#6


我觉得是2。

到第9行时,   
4. X2 x2=new X2();
5. X2 x3=new X2();
可以回收,而9.  x3=x2;则是
x3、x2共同指向8.x2=new X2();创建的对象。

所以是2。

#7


应该是2.
为什么楼上的感觉是 3 个呢?我感觉不出来3 个。
创建了3个对象,2个成为了垃圾。8、9行的代码说明有两个引用指向对象3#。

#8


本来是跟在gemouzhi(gemouzhi) 后面的,中间有人发言了。
晕。

#9


根据不同的JVM的GC机制,答案应该不确定,0和2都有可能.
根据ref来判断回收的话,前两个X2对象是相互引用的,答案是0.
但这样肯定是会造成内存泄漏的,所以现实中JVM都应该采用孤岛回收的策略.

2,认同.

#10


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");
    }

}

测试了一下,输出2次clear

#11


之所以感觉是因为,我觉的:最后那个对象的ref在网络stack上并不存活。

你是没感觉不是感觉不出来。

yqj2065(严千钧) 你贴一段你测试的代码我看看

#12


谢谢楼上的代码,结合TIJ的148-154,终于搞明白了一些,我还做了其他测试。很cool

谢谢simbas00

#13


原来是被回收的对象

#14


老大,你不会是以为创建的对象吧,嘎嘎。

#15


To gemouzhi:没感觉、感觉不出来?不要这样说。
既然有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持有。

#16


8后,x2.x为null
-----
我不这样认为,8后,x2.x不为null

#17


sorry,我可能理解的有问题,我再看一下

#18


8后,x2指向的对象是新对象啊,其成员变量x仅仅被默认初始化,当然是null了。

#19


yqj2065(严千钧) 你解释一下8后,x2.x为null,谢谢

#20


我是想说:

1,x2其成员变量x你认为在什么地方分配内存?

2,这个成员变量x为什么会在x2指向新对象的时候她指向null?因为这个对象原来是有所指的。

#21


x2其成员变量x的内存分配,一定在heap中,而x2本身则在stack中。

成员变量x为什么会在x2指向新对象的时候她指向null?
晕,上面说了啊。
“x2指向的对象是新对象啊,其成员变量x仅仅被默认初始化,当然是null了”

#22


x2其成员变量x的内存分配,一定在heap中。

恩,我到希望是这样,因为这样更好叫我理解,但对象的成员变量分配在heap上,你有根据吗?

有的话,给你加100分。

x2指向的对象是新对象,但是这个时候并没有进行gc,所以x2原来指向的堆上的对象还是存活的

而且我按simbas00给的代码打出x2.x都是@9664a1。这些都是小问题。

对象的成员变量分配在heap上,我还真没弄明白,你先找些根据。

这个GcTest 也是对象吧GcTest x2是她的成员吧,你的意思是x2也分配在heap上?

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;

#23


呵呵,朋友,
对象的成员变量分配在heap上,你有根据吗?
这是Java内存管理最基本的规定。对象的内存在heap分配,就是说的是对象的所有成员变量在heap分配空间啊。

x2也分配在heap上?
no,局部变量全部在stack中分配空间。

#24


给你加100分?呵呵,谢谢

我散过1000分的,我的信誉:93 就是那次搞下来的。

#25


“这个GcTest 也是对象吧GcTest x2是她的成员吧,你的意思是x2也分配在heap上?

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;

public GcTest g;
g是成员,x2不是,

#26


分是小问题,关键我要搞懂,嘎嘎,等我把这篇文章看完。

不就是分嘛,没问题。我先看一下,局部变量和对象的成员变量的内存分配。

对了。关于simbas00给的代码打出x2.x的地址的问题,也希望你能指教一下

#27


你的代码可能有问题。
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

#28


等我找找不同,just wait

public class GcTest {
    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");
    }

}

#29


晕我怎么打成x2了,恩,我了解,很好,这次的指教叫我清楚的了不少

#30


太cool了,代码我已OK了,还有,如果是这样全分配在堆上,java关于子对象访问父对象的变量

那是不是太强了,所以我一直不以为分配在堆上,当然,现在我在没找到官方资料之前无法说

什么,但是,嘎嘎,5分钟后等着领分,然后我来回答楼主的问题。

#31


新来的,向楼上的几位学习了。

#32


1.class X2{
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上的组织形式.

谢谢各位观看.

#33


我倒觉得是0,因为第9行之后还有一个对doComplexStuff()的调用。。。
再说是不是应该出了"}"外,垃圾回收机制才会生效呢?

我觉得关键是要弄清楚垃圾回收机制是在什么时候被调用的?
上面的各位都是在自己的代码中强制调用System.gc()才的得到结论。

#34


学习一下。

#35


提高...


欢迎有JAVA#JSP兴趣的加入技术群:15328132
(为了不让无关人员加入,请回答一个JAVA的简单问题久可以接受高手们的指点!)

#36


这道题似乎没有那么复杂,支持选 C 回收了 2 个,试解释如下:

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

--
运行到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

#37


答案是2个,没问题。但是使用finalize的测试是不对的。
上面大家分析的已经很不错了,我只是想说说上面的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个!

#38


The JVM is divided into four conceptual data spaces:

Class area, where the code and constants are kept

Java stack, which keeps track of which methods have been called and the data associated with each method invocation

Heap, where objects are kept

Native method stacks, for supporting native methods

#39


早上,就有同事问我有关这道题目的问题了,这么好的帖子,竟然没有注意到,顶一下!!!

#40


An object is ready to be garbage collected when it is no longer "alive." The rules for determining if an object is alive follow.

If there's a reference to the object on the stack, then it's alive.

If there's a reference to the object in a local variable, on the stack, or in a static field, then it's alive.

If a field of an alive object contains a reference to the object, then it's alive.

The JVM may internally keep references to certain objects, for example, to support native methods. These objects are alive.

#41


jFresH_MaN的解释,
正确与错误的解释。

“finalize测试是不对的”“gc是个不确定的行为,我们无法控制,JVM回收垃圾一直都是不可控的”,理论上是正确。使用finalize的测试方法 ,常常忽略了“可回收”与“被回收”的差别。

“题目中line9之后还有line10,这个是非常重要的,也就是说line9之后这个方法的作用域还没有结束”,
“而line10之后,就会有“结束作用域的局部对象”也符合垃圾回收的条件。”
“创建的3个对象都是局部的”
错误的或者说混乱的解释。

一个基本的观点:对象没有/不受词法作用域的限制,受词法作用域限制的是引用变量(或者叫句柄)。作用域结束后,句柄被清除,可能由于对象ref的最后一个持有者丧失而导致对象沦为垃圾。
不要混淆对象与句柄。
如果能够让对象方便的受词法作用域限制,Java中的对象就不需要在heap中分配内存了。

按照题目的问题,9后,垃圾对象是两个,当然此时使用finalize测试也是两个。

#42


无聊!是不是垃圾你关心它干嘛,又不用你释放!

#43


顺便说一下:对象的成员变量的内存分配全部在heap中,正如
liu_you(滴水藏海) 摘录的"Heap, where objects are kept"

但是,不同的JVM如何实现是另外一回事.

有文章介绍,有的JVM甚至可以在物理的寄存器中给对象分配内存.我们仍然把这时的物理的寄存器视为heap.

#44


heap和stack都是内存,但是使用了不同的组织形式,正如对象分配在heap上

绝对不会是随便的扔进heap内存,而我所要找的,就是要把,堆内存分配的结构和组织形式找到

因为这直接关系到,子对象对父对象成员变量的访问,

而不是笼统的说一下分配在堆上,那和直接说分配在内存里没有区别了

#45


To gemouzhi(gemouzhi) 

"第8行,我认为这里并不产生垃圾",正确!

#46


Heap, where objects are kept

等于没说,例如java的句柄池,方法区,操作数的栈,还有最重要的关于帧的分配

#47


两个

public class A {
    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");
    }

}

#48


To gemouzhi(gemouzhi) 
"我所要找的,就是要把,堆内存分配的结构和组织形式找到"
呵呵,有出息的家伙

#49


http://community.csdn.net/Expert/topic/4411/4411549.xml?temp=.9349787
希望 yqj2065(严千钧) 大哥能来这里踩一脚,我已没办法给分了

#50


我是比较痴迷于MFC的vtable和VCL的VMT。

java也是人做出来的,无论如何的高级,他都会留有上一代编译器的影子.

java也是人做出来的,我个人认为有可能会有高级的内存泄漏.

希望能和大家交流,因为我现在水平还不行,先看完,老外那本inside JVM也许会有启发.

然后回来发贴分享一下.

谢谢 yqj2065(严千钧) 大哥对我指教.

#1


3

#2


有没有人能解释一下啊?我是真的不懂

#3


我也学习一下,我也感觉是 3 个,但我测试的结果好象是 2 个。比较奇怪。

#4


8.         x2=new X2();
9.         x3=x2;
这时只有第8行的这个new X2对象被引用,所以不被回收,其余的第4,5 行的对象new X2()没有被引用所以被垃圾回收,所以我认为是2个。

#5


java里并不是以ref的判断来决定gc的

#6


我觉得是2。

到第9行时,   
4. X2 x2=new X2();
5. X2 x3=new X2();
可以回收,而9.  x3=x2;则是
x3、x2共同指向8.x2=new X2();创建的对象。

所以是2。

#7


应该是2.
为什么楼上的感觉是 3 个呢?我感觉不出来3 个。
创建了3个对象,2个成为了垃圾。8、9行的代码说明有两个引用指向对象3#。

#8


本来是跟在gemouzhi(gemouzhi) 后面的,中间有人发言了。
晕。

#9


根据不同的JVM的GC机制,答案应该不确定,0和2都有可能.
根据ref来判断回收的话,前两个X2对象是相互引用的,答案是0.
但这样肯定是会造成内存泄漏的,所以现实中JVM都应该采用孤岛回收的策略.

2,认同.

#10


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");
    }

}

测试了一下,输出2次clear

#11


之所以感觉是因为,我觉的:最后那个对象的ref在网络stack上并不存活。

你是没感觉不是感觉不出来。

yqj2065(严千钧) 你贴一段你测试的代码我看看

#12


谢谢楼上的代码,结合TIJ的148-154,终于搞明白了一些,我还做了其他测试。很cool

谢谢simbas00

#13


原来是被回收的对象

#14


老大,你不会是以为创建的对象吧,嘎嘎。

#15


To gemouzhi:没感觉、感觉不出来?不要这样说。
既然有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持有。

#16


8后,x2.x为null
-----
我不这样认为,8后,x2.x不为null

#17


sorry,我可能理解的有问题,我再看一下

#18


8后,x2指向的对象是新对象啊,其成员变量x仅仅被默认初始化,当然是null了。

#19


yqj2065(严千钧) 你解释一下8后,x2.x为null,谢谢

#20


我是想说:

1,x2其成员变量x你认为在什么地方分配内存?

2,这个成员变量x为什么会在x2指向新对象的时候她指向null?因为这个对象原来是有所指的。

#21


x2其成员变量x的内存分配,一定在heap中,而x2本身则在stack中。

成员变量x为什么会在x2指向新对象的时候她指向null?
晕,上面说了啊。
“x2指向的对象是新对象啊,其成员变量x仅仅被默认初始化,当然是null了”

#22


x2其成员变量x的内存分配,一定在heap中。

恩,我到希望是这样,因为这样更好叫我理解,但对象的成员变量分配在heap上,你有根据吗?

有的话,给你加100分。

x2指向的对象是新对象,但是这个时候并没有进行gc,所以x2原来指向的堆上的对象还是存活的

而且我按simbas00给的代码打出x2.x都是@9664a1。这些都是小问题。

对象的成员变量分配在heap上,我还真没弄明白,你先找些根据。

这个GcTest 也是对象吧GcTest x2是她的成员吧,你的意思是x2也分配在heap上?

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;

#23


呵呵,朋友,
对象的成员变量分配在heap上,你有根据吗?
这是Java内存管理最基本的规定。对象的内存在heap分配,就是说的是对象的所有成员变量在heap分配空间啊。

x2也分配在heap上?
no,局部变量全部在stack中分配空间。

#24


给你加100分?呵呵,谢谢

我散过1000分的,我的信誉:93 就是那次搞下来的。

#25


“这个GcTest 也是对象吧GcTest x2是她的成员吧,你的意思是x2也分配在heap上?

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;

public GcTest g;
g是成员,x2不是,

#26


分是小问题,关键我要搞懂,嘎嘎,等我把这篇文章看完。

不就是分嘛,没问题。我先看一下,局部变量和对象的成员变量的内存分配。

对了。关于simbas00给的代码打出x2.x的地址的问题,也希望你能指教一下

#27


你的代码可能有问题。
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

#28


等我找找不同,just wait

public class GcTest {
    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");
    }

}

#29


晕我怎么打成x2了,恩,我了解,很好,这次的指教叫我清楚的了不少

#30


太cool了,代码我已OK了,还有,如果是这样全分配在堆上,java关于子对象访问父对象的变量

那是不是太强了,所以我一直不以为分配在堆上,当然,现在我在没找到官方资料之前无法说

什么,但是,嘎嘎,5分钟后等着领分,然后我来回答楼主的问题。

#31


新来的,向楼上的几位学习了。

#32


1.class X2{
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上的组织形式.

谢谢各位观看.

#33


我倒觉得是0,因为第9行之后还有一个对doComplexStuff()的调用。。。
再说是不是应该出了"}"外,垃圾回收机制才会生效呢?

我觉得关键是要弄清楚垃圾回收机制是在什么时候被调用的?
上面的各位都是在自己的代码中强制调用System.gc()才的得到结论。

#34


学习一下。

#35


提高...


欢迎有JAVA#JSP兴趣的加入技术群:15328132
(为了不让无关人员加入,请回答一个JAVA的简单问题久可以接受高手们的指点!)

#36


这道题似乎没有那么复杂,支持选 C 回收了 2 个,试解释如下:

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

--
运行到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

#37


答案是2个,没问题。但是使用finalize的测试是不对的。
上面大家分析的已经很不错了,我只是想说说上面的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个!

#38


The JVM is divided into four conceptual data spaces:

Class area, where the code and constants are kept

Java stack, which keeps track of which methods have been called and the data associated with each method invocation

Heap, where objects are kept

Native method stacks, for supporting native methods

#39


早上,就有同事问我有关这道题目的问题了,这么好的帖子,竟然没有注意到,顶一下!!!

#40


An object is ready to be garbage collected when it is no longer "alive." The rules for determining if an object is alive follow.

If there's a reference to the object on the stack, then it's alive.

If there's a reference to the object in a local variable, on the stack, or in a static field, then it's alive.

If a field of an alive object contains a reference to the object, then it's alive.

The JVM may internally keep references to certain objects, for example, to support native methods. These objects are alive.

#41


jFresH_MaN的解释,
正确与错误的解释。

“finalize测试是不对的”“gc是个不确定的行为,我们无法控制,JVM回收垃圾一直都是不可控的”,理论上是正确。使用finalize的测试方法 ,常常忽略了“可回收”与“被回收”的差别。

“题目中line9之后还有line10,这个是非常重要的,也就是说line9之后这个方法的作用域还没有结束”,
“而line10之后,就会有“结束作用域的局部对象”也符合垃圾回收的条件。”
“创建的3个对象都是局部的”
错误的或者说混乱的解释。

一个基本的观点:对象没有/不受词法作用域的限制,受词法作用域限制的是引用变量(或者叫句柄)。作用域结束后,句柄被清除,可能由于对象ref的最后一个持有者丧失而导致对象沦为垃圾。
不要混淆对象与句柄。
如果能够让对象方便的受词法作用域限制,Java中的对象就不需要在heap中分配内存了。

按照题目的问题,9后,垃圾对象是两个,当然此时使用finalize测试也是两个。

#42


无聊!是不是垃圾你关心它干嘛,又不用你释放!

#43


顺便说一下:对象的成员变量的内存分配全部在heap中,正如
liu_you(滴水藏海) 摘录的"Heap, where objects are kept"

但是,不同的JVM如何实现是另外一回事.

有文章介绍,有的JVM甚至可以在物理的寄存器中给对象分配内存.我们仍然把这时的物理的寄存器视为heap.

#44


heap和stack都是内存,但是使用了不同的组织形式,正如对象分配在heap上

绝对不会是随便的扔进heap内存,而我所要找的,就是要把,堆内存分配的结构和组织形式找到

因为这直接关系到,子对象对父对象成员变量的访问,

而不是笼统的说一下分配在堆上,那和直接说分配在内存里没有区别了

#45


To gemouzhi(gemouzhi) 

"第8行,我认为这里并不产生垃圾",正确!

#46


Heap, where objects are kept

等于没说,例如java的句柄池,方法区,操作数的栈,还有最重要的关于帧的分配

#47


两个

public class A {
    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");
    }

}

#48


To gemouzhi(gemouzhi) 
"我所要找的,就是要把,堆内存分配的结构和组织形式找到"
呵呵,有出息的家伙

#49


http://community.csdn.net/Expert/topic/4411/4411549.xml?temp=.9349787
希望 yqj2065(严千钧) 大哥能来这里踩一脚,我已没办法给分了

#50


我是比较痴迷于MFC的vtable和VCL的VMT。

java也是人做出来的,无论如何的高级,他都会留有上一代编译器的影子.

java也是人做出来的,我个人认为有可能会有高级的内存泄漏.

希望能和大家交流,因为我现在水平还不行,先看完,老外那本inside JVM也许会有启发.

然后回来发贴分享一下.

谢谢 yqj2065(严千钧) 大哥对我指教.