`

Java中的垃圾回收与对象生命周期

阅读更多
    在<<Java编程思想>>书中,作者对垃圾回收的精要概述:"基于系统平台自适应的停止-复制"垃圾回收技术和"sun早期自适应的标记-清扫"垃圾回收技术。当然,对一个系统来说,初始化和清理是系统整个运行过程中大两大核心"进程",我觉得"初始化"和"清理"已经称为一种专业术语,不管是小段代码,一个大程序,一个系统,甚至是软件架构,在其本身构建和运行过程中,垃圾回收如同模拟现实世界场景一样,已称为一种模式,一种"行为"或是对象的"习惯"。

    模拟现实场景来说,人是如何清理垃圾的,被丢弃的废纸,废品... 人会有专门的垃圾清理站或是保洁公司来处理这些“已耗尽”的能量,使其在土壤中循环再造。然而,这些垃圾也可以看做是"现实对象"。然而要模拟到用计算机实现这种垃圾回收系统,定是很有趣的事情,或许你早已在脑海中构建一副用计算机实现的垃圾回收场景,可那画面的内幕还是需要细细设计。于是有兴趣参考优化编程,java垃圾回收有向图等资料,简单地整理了一些基本的概念,分享之。若是很了解垃圾回收内幕的高手或是大师,还望你指点,我是这方面的新手,还在门前虚心求教和批评指正。

1. 垃圾回收

   垃圾回收是Java程序设计中内存管理的核心概念,JVM的内存管理机制被称为垃圾回收机制。

  一个对象创建后被放置在JVM的堆内存中,当永远不再引用这个对象时,它将被JVM在堆内存中回收。被创建的对象不能再生,同时也没有办法通过程序语句释放它们。即当对象在JVM运行空间中无法通过根集合到达(找到)时,这个对象被称为垃圾对象。根集合是由类中的静态引用域与本地引用域组成的。JVM通过根集合索引对象。

    在做Java应用开发时经常会用到由JVM管理的两种类型的内存:堆内存和栈内存。简单来讲,堆内存主要用来存储程序在运行时创建或实例化的对象与变量。例如通过new关键字创建的对象。而栈内存则是用来存储程序代码中声明为静态或非静态的方法。


(1) 堆内存

    堆内存在JVM启动的时候被创建,堆内存中所存储的对象可以被JVM自动回收,不能通过其他外部手段回收,也就是说开发人员无法通过添加相关代码的手段来回收堆内存中的对象。堆内存通常情况下被分为两个区域:新对象区域与老对象区域。

    新对象区域:又可细分为三个小区域:伊甸园区域、From区域与To区域。伊甸园区域用来保存新创建的对象,它就像一个堆栈,新的对象被创建,就像指向该栈的指针在增长一样,当伊甸园区域中的对象满了之后,JVM系统将要做到可达性测试,主要任务是检测有哪些对象由根集合出发是不可达的,这些对象就可以被JVM回收,并且将所有的活动对象从伊甸园区域拷贝到To区域,此时一些对象将发生状态交换,有的对象就从To区域被转移到From区域,此时From区域就有了对象。上面对象迁移的整个过程,都是由JVM控制完成的。

    老对象区域:在老对象区域中的对象仍然会有一个较长的生命周期,大多数的JVM系统垃圾对象,都是源于"短命"对象,经过一段时间后,被转入老对象区域的对象,就变成了垃圾对象。此时,它们都被打上相应的标记,JVM系统将会自动回收这些垃圾对象,建议不要频繁地强制系统作垃圾回收,这是因为JVM会利用有限的系统资源,优先完成垃圾回收工作,导致应用无法快速地响应来自用户端的请求,这样会影响系统的整体性能。


(2) 栈内存

    堆内存主要用来存储程序在运行时创建或实例化的对象与变量。例如通过new关键字创建的对象。而栈内存则是用来存储程序代码中声明为静态或非静态的方法。

2. JVM中对象的生命周期

   在JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:
   创建阶段;
   应用阶段;
   不可视阶段;
   不可到达阶段;
   可收集阶段;
   终结阶段;
   释放阶段
 

   上面这7个阶段,构成了JVM中对象的完整的生命周期。


   (1) 创建阶段

       在对象的创建阶段,系统主要通过下面的步骤,完成对象的创建过程:
    
       <1> 为对象分配存储空间;
       <2> 开始构造对象;
       <3> 从超类到子类对static成员进行初始化;
       <4> 超类成员变量按顺序初始化,递归调用超类的构造方法;
       <5> 子类成员变量按顺序初始化,子类构造方法调用。

       在创建对象时应注意几个关键应用规则:
      
       <1> 避免在循环体中创建对象,即使该对象占用内存空间不大。
       <2> 尽量及时使对象符合垃圾回收标准。比如 myObject = null。
       <3> 不要采用过深的继承层次。
       <4> 访问本地变量优于访问类中的变量。


      
比如:
       for (int i = 0; i < 10000; i++) {
             Object obj = new Object();
             System.out.println(obj);
       }

       和
       Object obj = null;
       for (int i = 0; i < 10000; i++) {
             obj = new Object();
             System.out.println(obj);
       }


       这里修正一下,在绝对情况下,效率还是上面的要好, 因为后面的多了一条初始化语句。
        而且各自作用域不同。 谢谢各位~~

   (2) 应用阶段

       在对象的引用阶段,对象具备如下特征:

      <1> 系统至少维护着对象的一个强引用(Strong Reference);
      <2> 所有对该对象的引用全部是强引用(除非我们显示地适用了:软引用(Soft Reference)、弱引用(Weak Reference)或虚引用(Phantom Reference)).


      强引用(Strong Reference):是指JVM内存管理器从根引用集合出发遍历堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,这个对象的引用就被称为强引用。

       软引用(Soft Reference):软引用的主要特点是有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此内存足够时它们通常不被回收。另外这些引用对象还能保证在Java抛出OutOfMemory异常之前,被设置为null。它可以用于实现一些常用资源的缓存,实现Cache功能,保证最大限度地使用内存你而不引起OutOfMemory。

                              
下面是软引用的实现代码:

                                import java.lang.ref.SoftReference;
                                ...
                                
                                A a = new A();
                                ...

                                // 使用a
                                ...
                                 
                                // 使用完了a, 将它设置为soft引用类型,并且释放强引用
                                SoftReference sr = new SoftReference(a);
                                a = null;
                                ...

                                // 下次使用时
			        if (sr != null) {
 				    a = sr.get();
				} else {
				    // GC由于低内存,已释放a,因此需要重新装载
                                    a = new A();
				    sr = new SoftReference(a);
				}


                                软引用技术的引进使Java应用可以更好地管理内存,稳定系统,防止系统内存溢出,避免系统崩溃。因此在处理一些占用内存较大且生命周期较长,但使用并不繁地对象时应尽量应用该技术。提高系统稳定性。
            
                                     
       弱引用(Weak Reference):弱应用对象与软引用对象的最大不同就在于:GC在进行垃圾回收时,需要通过算法检查是否回收Soft应用对象,而对于Weak引用,GC总是进行回收。Weak引用对象更容易、更快地被GC回收。Weak引用对象常常用于Map结构中。
                             
 下面是弱引用的实现代码:

                                import java.lang.ref.WeakReference;
                                ...
                                
                                A a = new A();
                                ...

                                // 使用a
                                ...
                                 
                                // 使用完了a, 将它设置为Weak引用类型,并且释放强引用
                                WeakReference wr = new WeakReference(a);
                                a = null;
                                ...

                                // 下次使用时
			        if (wr != null) {
 				    a = wr.get();
				} else {
                                    a = new A();
				    wr = new WeakReference(a);
				}
   
  
虚引用(Phantom Reference): 虚引用的用途较少,主要用于辅助finalize函数的使用。

虚引用(Phantom Reference)对象指一些执行完了finalize函数,并为不可达对象,但是还没有被GC回收的对象。这种对象可以辅助finalize进行一些后期的回收工作,我们通过覆盖了Refernce的clear()方法,增强资源回收机制的灵活性。

      
       在实际程序设计中一般很少使用弱引用和虚引用,是用软引用的情况较多,因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。


    (3) 不可视阶段
         当一个对象处于不可视阶段,说明我们在其他区域的代码中已经不可以在引用它,其强引用已经消失,例如,本地变量超出了其可视
的范围。

     
 try {
             Object localObj = new Object();
	     localObj.doSomething();
       } catch (Exception e) {
           e.printStackTrace();
       }

       if (true) {
	    // 此区域中localObj 对象已经不可视了, 编译器会报错。
	    localObj.doSomething();
       }
   

   (4) 不可到达阶段
       处于不可达阶段的对象在虚拟机的对象引用根集合中再也找不到直接或间接地强引用,这些对象一般是所有线程栈中的临时变量。所有已经装载的静态变量或者是对本地代码接口的引用。


   (5) 可收集阶段、终结阶段与释放阶段

       当一个对象处于可收集阶段、终结阶段与释放阶段时,该对象有如下三种情况:

       <1> 回收器发现该对象已经不可达。

       <2> finalize方法已经被执行。

       <3> 对象空间已被重用。

     
       
      
分享到:
评论
28 楼 wangzaixiang 2010-06-22  
而栈内存则是用来存储程序代码中声明为静态或非静态的方法

请问楼主,你自己明白是什么意思吗?麻烦你把那段英语原文贴出来,再好好查查字典。
码字其实并不重要,真正消化理解才是正章。
27 楼 wangzaixiang 2010-06-22  
晚上再看看帖子,略有感触。

1、这个初哥不理解我的问题也就罢了,放屁的词语也出来了。现在,不知道到底明白是我在放屁还是楼主搞错了。

2、谢谢mercyblitz替我回复,与我的表述基本相符,但可能存在笔误,我再修订一下。

每一行执行代码称为一帧 =》 应为每一次函数调用对应一帧。

引用
确实没有差别,理由:这两代码都生成了10000个对象,楼主对引用的理解有误。第二段代码中,相对与第一段而言,少开辟了几个栈对象,也就是说 Object obj只是个一个标示,关键是new了10000次,因此在执行效率和内存消耗没有不同,只是变量的作用域变化了。

其实,第二段代码和第一段代码在帧上分配的变量是一样的,也是一个栈变量(不合适成为栈对象)。

4、当对象处于释放状态后,空间状态为“已被重用”,这个是典型的字面翻译,其错误不值一提。

感觉楼主应该是一个很好学的程序员,不过,目前,Java水平还处在幼儿园级别,谦虚程度又颇有博士生的感觉。谈到放屁二字,我稍微吹吹水,在JVM上,我小有10余年研究,不算专家的话,也是略有精通的人了。本想指点楼主一二,却可惜被反批了一顿,笑笑飘过。

26 楼 beneo 2010-06-22  
J-catTeam 写道
比如: 
       不要写成: 
       for (int i = 0; i < 10000; i++) { 
             Object obj = new Object(); 
             System.out.println(obj); 
       } 
 
       要写成: 
       Object obj = null; 
       for (int i = 0; i < 10000; i++) { 
             obj = new Object(); 
             System.out.println(obj); 
       }

看应用场景的


这样写会容易出现陷阱。
我倒觉得
             Object obj = new Object();  
             System.out.println(obj); 
             obj = null;

这个会帮助GC
25 楼 coffeesweet 2010-06-21  
对楼主提出的软应用的好处还是不太理解。
比如为什么
"软引用技术的引进使Java应用可以更好地管理内存,稳定系统,防止系统内存溢出,避免系统崩溃"???
24 楼 mercyblitz 2010-06-21  
maozj 写道
wangzaixiang 写道
写了很多,错误不少。
1. 而栈内存则是用来存储程序代码中声明为静态或非静态的方法。
完全错误的表达。

2、为对象分配存储空间;
       <2> 开始构造对象;
       <3> 从超类到子类对static成员进行初始化;
       <4> 超类成员变量按顺序初始化,递归调用超类的构造方法;
       <5> 子类成员变量按顺序初始化,子类构造方法调用。
static的初始化与new操作没有任何关系。

3、比如:
       不要写成:
       for (int i = 0; i < 10000; i++) {
             Object obj = new Object();
             System.out.println(obj);
       }

       要写成:
       Object obj = null;
       for (int i = 0; i < 10000; i++) {
             obj = new Object();
             System.out.println(obj);
       }
完全错误。两者在运行时几无差别,前置在编码风格上更为合理。

4、 (5) 可收集阶段、终结阶段与释放阶段
       当一个对象处于可收集阶段、终结阶段与释放阶段时,该对象有如下三种情况:

       <1> 回收器发现该对象已经不可达。

       <2> finalize方法已经被执行。

       <3> 对象空间已被重用。
前面的理解都不正确,这里的表述更为问题多多。

1. 而栈内存则是用来存储程序代码中声明为静态或非静态的方法。
完全错误的表达。  请您解释下?

2. static的初始化与new操作没有任何关系。放屁

3.完全错误。两者在运行时几无差别,前置在编码风格上更为合理。 理由?

4. 请解释。


呵呵,我来解释吧,首先楼主,你要明白一点,wangzaixiang说的是对的。为什么?

1.栈内存是由栈帧(frame)组成的,在Java代码中的,每一行执行代码称为一帧。比如Object obj=null;obj这样的标示对象会保存在栈里面。同时,方法参数对象标示也在栈中。对象的实际物理保存都在堆中。由于Java的重进入,
所以栈对象是线程安全,而堆是JVM线程共享的,因此需要合理的同步。

2.确实没有关系,static成员隶属于类对象,类的static成员的初始化是在ClassLoader第一次加载该类的时候。和new确实没有什么关系,只不过第一次出现new SomeObject的时候,会加载SomeObject,然后静态成员初始化了。楼主这里就误会了,不一定new 才是加载类的开始,通过调用类的静态可访问的方法也是可以的。

3.确实没有差别,理由:这两代码都生成了10000个对象,楼主对引用的理解有误。第二段代码中,相对与第一段而言,少开辟了几个栈对象,也就是说Object obj只是个一个标示,关键是new了10000次,因此在执行效率和内存消耗没有不同,只是变量的作用域变化了。

4.我的理解是:
  <1> 比如方法中的局部对象,并不需要JVM标记不可达,在方法执行完之后,马上就被回收。这就是为什么不需要在局部对象使用后,显示地设置为null.
  <2>finalize 不一定可靠,或者被调用。规范中没有规定,垃圾收集器必须要在对象回收时,调用这种方法或者并不是每个对象回收时均被调用。不等同于free或者C++的析构。
  <3>重用是肯定的,但是对象空间能不能马上重用,很难说,G1的算法和CMS等算法不同。G1是等大小区域,相对来说比较容易。CMS,我没有记错的话,是采用的碎片空间移动。



23 楼 maozj 2010-06-21  
mercyblitz 写道
maozj 写道
joehe 写道
i2534 写道
J-catTeam 写道
比如: 
       不要写成: 
       for (int i = 0; i < 10000; i++) { 
             Object obj = new Object(); 
             System.out.println(obj); 
       } 
 
       要写成: 
       Object obj = null; 
       for (int i = 0; i < 10000; i++) { 
             obj = new Object(); 
             System.out.println(obj); 
       }

看应用场景的

貌似前几天javaeye上有个帖子阐述了这个问题,说的是两个方式现在的jvm已经是一样的速度了.


这点不错,不能一概而论,会误导观众的

你能说说这两段代码的区别吗


这两代码都生成了10000个对象,楼主对引用的理解有误。第二段代码中,相对与第一段而言,少开辟了几个栈对象,也就是说Object obj只是个一个标示,关键是new了10000次,因此在执行效率和内存消耗没有不同,只是变量的作用域变化了。


-------------------------
已修正~~
22 楼 maozj 2010-06-21  
已修正~~ 写的很好
21 楼 mercyblitz 2010-06-21  
maozj 写道
joehe 写道
i2534 写道
J-catTeam 写道
比如: 
       不要写成: 
       for (int i = 0; i < 10000; i++) { 
             Object obj = new Object(); 
             System.out.println(obj); 
       } 
 
       要写成: 
       Object obj = null; 
       for (int i = 0; i < 10000; i++) { 
             obj = new Object(); 
             System.out.println(obj); 
       }

看应用场景的

貌似前几天javaeye上有个帖子阐述了这个问题,说的是两个方式现在的jvm已经是一样的速度了.


这点不错,不能一概而论,会误导观众的

你能说说这两段代码的区别吗


这两代码都生成了10000个对象,楼主对引用的理解有误。第二段代码中,相对与第一段而言,少开辟了几个栈对象,也就是说Object obj只是个一个标示,关键是new了10000次,因此在执行效率和内存消耗没有不同,只是变量的作用域变化了。
20 楼 joinhack 2010-06-21  
呵呵,楼主扯远了,扯远了,偏离讨论方向了。顺便问下作者在那个公司。
19 楼 61234865 2010-06-21  
maozj 写道
61234865 写道
首先对作者表示感谢,上面的内容,因为我也不是java方面的高手,对于正确与否,我就不做评价了,但有一点要说明的是,对象用完后,一旦不再使用就置空,这个做法我深表赞同,因为我们现在的项目中就大量使用了此技巧,我们的项目是多线程的,在没有进行置空操作时,内存要1G以上才能稳定运行,现在进行置空处理后,200多M的内存就能很稳定的运行了,性能提升是巨大的。其实以前我也认为当代码中所谓的“不可见”出现后,JVM会自动 把对象GC的,但通过现在这个项目发现,根本不是这么回事。呵呵 ,我只是用我们现在项目的实例来说明强行指定null会对性能带来巨大的提升,尤其是多线程的时候更明显。就说这么多吧,至于其它的,我不想多讨论,因为个人认为能解决问题才是最终目的

 
   "其实以前我也认为当代码中所谓的“不可见”出现后,JVM会自动 把对象GC的,但通过现在这个项目发现,根本不是这么回事。"

    恩,这个你验证过了,我表示赞同。我也是在摸索阶段中,但不确定怎么样的验证才能足以说明大师的"理论"。

    "个人认为能解决问题才是最终目的...”这句话曾是我以前所信奉的,毕竟在公司老板要的就是你要解决问题,这才是他最想要的,他不管你使用何种手段,何种方法只要把问题解决,不在出现那个问题了,他就会点头。

     但是在那些技术总监眼里,它们根本不把这放在眼里(可能是针对技术的),他不然要求你把问题解决了,还要用合理的,最有效率的办法,只有这样,才是所谓的最程序员职业的尊重。不谈那么多了,其实,说的透彻点,80%的人都会认同“解决问题才是最终目的”, 毕竟现代社会是个高消费,高效率的社会。。。

我想是你理解错误的我的意思了,我说的“个人认为能解决问题才是最终目的”是指在技术框架的和技术规范的前提下解决问题,并不是说哪有问题改哪,没有一点逻辑性和规范性,呵呵 ,都是做软件的,说白了,在相同的能力水平的前提下,代码的质量,关键是看个人的责任心了
18 楼 maozj 2010-06-21  
61234865 写道
首先对作者表示感谢,上面的内容,因为我也不是java方面的高手,对于正确与否,我就不做评价了,但有一点要说明的是,对象用完后,一旦不再使用就置空,这个做法我深表赞同,因为我们现在的项目中就大量使用了此技巧,我们的项目是多线程的,在没有进行置空操作时,内存要1G以上才能稳定运行,现在进行置空处理后,200多M的内存就能很稳定的运行了,性能提升是巨大的。其实以前我也认为当代码中所谓的“不可见”出现后,JVM会自动 把对象GC的,但通过现在这个项目发现,根本不是这么回事。呵呵 ,我只是用我们现在项目的实例来说明强行指定null会对性能带来巨大的提升,尤其是多线程的时候更明显。就说这么多吧,至于其它的,我不想多讨论,因为个人认为能解决问题才是最终目的

 
   "其实以前我也认为当代码中所谓的“不可见”出现后,JVM会自动 把对象GC的,但通过现在这个项目发现,根本不是这么回事。"

    恩,这个你验证过了,我表示赞同。我也是在摸索阶段中,但不确定怎么样的验证才能足以说明大师的"理论"。

    "个人认为能解决问题才是最终目的...”这句话曾是我以前所信奉的,毕竟在公司老板要的就是你要解决问题,这才是他最想要的,他不管你使用何种手段,何种方法只要把问题解决,不在出现那个问题了,他就会点头。

     但是在那些技术总监眼里,它们根本不把这放在眼里(可能是针对技术的),他不然要求你把问题解决了,还要用合理的,最有效率的办法,只有这样,才是所谓的最程序员职业的尊重。不谈那么多了,其实,说的透彻点,80%的人都会认同“解决问题才是最终目的”, 毕竟现代社会是个高消费,高效率的社会。。。
17 楼 61234865 2010-06-21  
首先对作者表示感谢,上面的内容,因为我也不是java方面的高手,对于正确与否,我就不做评价了,但有一点要说明的是,对象用完后,一旦不再使用就置空,这个做法我深表赞同,因为我们现在的项目中就大量使用了此技巧,我们的项目是多线程的,在没有进行置空操作时,内存要1G以上才能稳定运行,现在进行置空处理后,200多M的内存就能很稳定的运行了,性能提升是巨大的。其实以前我也认为当代码中所谓的“不可见”出现后,JVM会自动 把对象GC的,但通过现在这个项目发现,根本不是这么回事。呵呵 ,我只是用我们现在项目的实例来说明强行指定null会对性能带来巨大的提升,尤其是多线程的时候更明显。就说这么多吧,至于其它的,我不想多讨论,因为个人认为能解决问题才是最终目的
16 楼 maozj 2010-06-21  
joinhack 写道
  for (int i = 0; i < 10000; i++) { 
             Object obj = new Object(); 
             System.out.println(obj); 
       } 
 
       要写成: 
       Object obj = null; 
       for (int i = 0; i < 10000; i++) { 
             obj = new Object(); 
             System.out.println(obj); 
       }
大家都感觉作者说的是错误的,但是并没有说出为什么,因此作者毛了,呵呵
其实,作者的意思是这么写会造成很多引用留在栈里面,但是作者还有个东西没有考虑,就是作用域。
句柄会随着作用域消失而消失,因此上面的2种写法,对于句柄来说不会不断扩大,作者可以放心使用。

恩 成很多引用留在栈里面 说的正确。。。
Object obj = null;  后者还多了一条初始化

您的说法 完全接受。。。 表述不错 足见很有方法哲理~~
15 楼 joinhack 2010-06-21  
  for (int i = 0; i < 10000; i++) { 
             Object obj = new Object(); 
             System.out.println(obj); 
       } 
 
       要写成: 
       Object obj = null; 
       for (int i = 0; i < 10000; i++) { 
             obj = new Object(); 
             System.out.println(obj); 
       }
大家都感觉作者说的是错误的,但是并没有说出为什么,因此作者毛了,呵呵
其实,作者的意思是这么写会造成很多引用留在栈里面,但是作者还有个东西没有考虑,就是作用域。
句柄会随着作用域消失而消失,因此上面的2种写法,对于句柄来说不会不断扩大,作者可以放心使用。
14 楼 maozj 2010-06-21  
没有任何关系? 这里表述的重点是顺序和关联, 书本上说new与static没有任何关系了吗? 如果说了,就是对的吗? 当然研究它们的关系没得意义
13 楼 maozj 2010-06-21  
new的时候会载入类吗? 载入类的时候会执行static、static快吗? 执行static时会初始化吗?
12 楼 maozj 2010-06-21  
wangzaixiang 写道
maozj 写道
i2534 写道
J-catTeam 写道
比如: 
       不要写成: 
       for (int i = 0; i < 10000; i++) { 
             Object obj = new Object(); 
             System.out.println(obj); 
       } 
 
       要写成: 
       Object obj = null; 
       for (int i = 0; i < 10000; i++) { 
             obj = new Object(); 
             System.out.println(obj); 
       }

看应用场景的

貌似前几天javaeye上有个帖子阐述了这个问题,说的是两个方式现在的jvm已经是一样的速度了.


----------------------

恩, 你这提法正确 现在JVM速度可以媲美了的 呵呵


我没有实际测试,但我可以肯定:
从JDK1.1开始,到现在的JDK1.6,后面这段代码都不可能比前面的代码快,理论上只会更慢,因为后者还多了一条初始化指令。
不信,你尝试用javap -c看看。
有哪位认为第二种情况会更快的(哪怕是千万分之一),说说你们的想法?


static的初始化与new操作没有任何关系。 居然在帖子下言论出这样的语句, 不是想发脾气,而是忍不住书本说明带来的误解~~ 更忍不住作为一名程序员对问题的理解和表达~~~ 以上纯属主观情绪,不针对人,只针对表述
11 楼 maozj 2010-06-21  
wangzaixiang 写道
写了很多,错误不少。
1. 而栈内存则是用来存储程序代码中声明为静态或非静态的方法。
完全错误的表达。

2、为对象分配存储空间;
       <2> 开始构造对象;
       <3> 从超类到子类对static成员进行初始化;
       <4> 超类成员变量按顺序初始化,递归调用超类的构造方法;
       <5> 子类成员变量按顺序初始化,子类构造方法调用。
static的初始化与new操作没有任何关系。

3、比如:
       不要写成:
       for (int i = 0; i < 10000; i++) {
             Object obj = new Object();
             System.out.println(obj);
       }

       要写成:
       Object obj = null;
       for (int i = 0; i < 10000; i++) {
             obj = new Object();
             System.out.println(obj);
       }
完全错误。两者在运行时几无差别,前置在编码风格上更为合理。

4、 (5) 可收集阶段、终结阶段与释放阶段
       当一个对象处于可收集阶段、终结阶段与释放阶段时,该对象有如下三种情况:

       <1> 回收器发现该对象已经不可达。

       <2> finalize方法已经被执行。

       <3> 对象空间已被重用。
前面的理解都不正确,这里的表述更为问题多多。

1. 而栈内存则是用来存储程序代码中声明为静态或非静态的方法。
完全错误的表达。  请您解释下?

2. static的初始化与new操作没有任何关系。放屁

3.完全错误。两者在运行时几无差别,前置在编码风格上更为合理。 理由?

4. 请解释。
10 楼 wangzaixiang 2010-06-21  
maozj 写道
i2534 写道
J-catTeam 写道
比如: 
       不要写成: 
       for (int i = 0; i < 10000; i++) { 
             Object obj = new Object(); 
             System.out.println(obj); 
       } 
 
       要写成: 
       Object obj = null; 
       for (int i = 0; i < 10000; i++) { 
             obj = new Object(); 
             System.out.println(obj); 
       }

看应用场景的

貌似前几天javaeye上有个帖子阐述了这个问题,说的是两个方式现在的jvm已经是一样的速度了.


----------------------

恩, 你这提法正确 现在JVM速度可以媲美了的 呵呵


我没有实际测试,但我可以肯定:
从JDK1.1开始,到现在的JDK1.6,后面这段代码都不可能比前面的代码快,理论上只会更慢,因为后者还多了一条初始化指令。
不信,你尝试用javap -c看看。
有哪位认为第二种情况会更快的(哪怕是千万分之一),说说你们的想法?
9 楼 wangzaixiang 2010-06-21  
写了很多,错误不少。
1. 而栈内存则是用来存储程序代码中声明为静态或非静态的方法。
完全错误的表达。

2、为对象分配存储空间;
       <2> 开始构造对象;
       <3> 从超类到子类对static成员进行初始化;
       <4> 超类成员变量按顺序初始化,递归调用超类的构造方法;
       <5> 子类成员变量按顺序初始化,子类构造方法调用。
static的初始化与new操作没有任何关系。

3、比如:
       不要写成:
       for (int i = 0; i < 10000; i++) {
             Object obj = new Object();
             System.out.println(obj);
       }

       要写成:
       Object obj = null;
       for (int i = 0; i < 10000; i++) {
             obj = new Object();
             System.out.println(obj);
       }
完全错误。两者在运行时几无差别,前置在编码风格上更为合理。

4、 (5) 可收集阶段、终结阶段与释放阶段
       当一个对象处于可收集阶段、终结阶段与释放阶段时,该对象有如下三种情况:

       <1> 回收器发现该对象已经不可达。

       <2> finalize方法已经被执行。

       <3> 对象空间已被重用。
前面的理解都不正确,这里的表述更为问题多多。

相关推荐

    Java 详解垃圾回收与对象生命周期

    Java垃圾回收与对象生命周期是Java程序设计中至关重要的概念,主要涉及到JVM内存管理机制。在Java中,垃圾回收机制负责自动管理堆内存,确保在程序运行过程中有效地使用内存资源,避免内存泄漏。 1. 垃圾回收: - ...

    Java中对象的生命周期 ..doc

    在Java中,对象的生命周期是指从对象被创建到最终被垃圾回收器回收这段时间。理解对象的生命周期对于有效地管理和优化Java应用程序至关重要。 #### 二、对象的创建 1. **对象生命周期的开始**: - 当对象被创建时...

    java高级之垃圾回收机制

    本文将详细介绍Java中的垃圾回收机制及其工作原理,并探讨JVM如何管理和优化垃圾回收过程。 #### 二、JVM内存模型 JVM内存模型主要包括永久代(Permanent Generation, PermGen)、堆(Heap)和栈(Stack)三大部分。值得...

    Java垃圾回收机制总结

    Java垃圾回收机制是Java虚拟机(JVM)中的一种机制,用于防止内存泄露和有效地使用空闲的内存。垃圾回收机制的主要目的是为了回收无用的对象占用的内存空间,使该空间可被程序再次使用。 垃圾回收机制的算法有多种...

    Java垃圾回收原理

    新生代中的对象生命周期通常较短,因此这里频繁发生垃圾回收;而老年代的对象生命周期较长,垃圾回收频率较低。分代收集理论利用这一特点,提高垃圾回收效率。 ##### 4.2 内存分配与回收 当新对象创建时,首先尝试...

    Java垃圾回收详解

    #### 对象的生命周期与垃圾回收触发条件 当使用`new`关键字创建一个对象后,并没有相应的`delete`操作来显式地释放该对象所占用的内存。在完成对某个对象的使用后,可以通过以下方式停止该对象的引用: - 将引用...

    java垃圾回收器代码举例

    - Java内存管理的核心是对象生命周期的管理,当一个对象不再被引用时,垃圾回收器会将其占用的内存空间回收。 2. **垃圾回收器的工作原理** - **可达性分析**:垃圾回收器通过一系列称为“根”(如局部变量、静态...

    java C#垃圾回收算法分析

    新生代对象生命周期短,使用复制算法;老年代对象生存时间长,使用标记-清除或标记-整理算法。 - **增量收集(Incremental GC)**:为了减少长时间暂停(Stop-the-World)现象,将垃圾回收过程分成多个小步骤,每次...

    JAVA垃圾回收面试个人总结.doc

    Java垃圾回收机制是Java编程中一个非常重要的概念,尤其在面试和实际开发中常常被讨论。垃圾回收(Garbage Collection, GC)是Java虚拟机自动管理内存的一种方式,旨在自动识别并释放不再使用的对象,从而避免内存...

    Java与C#的垃圾回收机制

    本文将深入对比Java与C#这两种广泛使用的编程语言中的垃圾回收机制,帮助开发者更好地理解它们的工作原理以及差异。 #### 二、Java的垃圾回收机制 ##### 2.1 Java内存区域 Java虚拟机(JVM)将内存划分为几个主要...

    java内存管理与垃圾回收

    Java 内存管理与垃圾回收是Java编程中至关重要的概念,它们确保了程序的稳定运行和内存的有效利用。Java在JVM(Java Virtual Machine)上运行,内存主要分为两个主要区域:栈(Stack)和堆(Heap)。 栈主要用于...

    JAVA垃圾回收机制

    Java垃圾回收机制(GC)是Java编程语言的关键特性,它自动管理内存,释放不再使用的对象,以防止内存泄漏。GC的运作方式主要有两种策略:引用计数和对象引用遍历。 引用计数是一种简单但不完美的方法。每个对象都有...

    java垃圾回收(gc)机制详解.pdf

    Java垃圾回收(GC)机制是Java语言管理内存的自动化机制,它能够自动释放不再使用的内存空间,从而避免内存泄漏和程序崩溃等问题。在介绍Java GC机制之前,我们首先要了解垃圾回收的目的和意义。在任何程序中,内存...

    java垃圾回收技术,面试会问

    ### Java垃圾回收技术详解 #### 一、引言 在现代软件开发中,Java作为一种广泛使用的编程语言,其垃圾回收机制(Garbage Collection, GC)是面试和技术交流中经常提及的话题之一。尤其对于那些深入研究Java内存...

    Java垃圾回收机制

    在Java中,对象的生命周期是由垃圾回收器来管理的,它自动释放不再被程序引用的对象,从而避免了内存泄漏等问题。 #### 三、垃圾回收的意义 在传统语言如C++中,程序员需要手动管理对象的内存,这意味着对象所占的...

    java虚拟机垃圾回收详解

    本文将深入探讨Java垃圾回收的基本原理、过程以及相关的配置选项。 垃圾回收的目的是在程序运行过程中自动识别并释放那些不再使用的对象所占用的内存空间。Java中的垃圾回收主要包括三个关键步骤:标记、扫描和清除...

    Java虚拟机和Java程序的生命周期?

    ### Java虚拟机与Java程序的生命周期 #### 一、Java虚拟机(JVM)概述 Java虚拟机(JVM)是一种可以执行Java字节码的虚拟机。它为Java应用程序提供了一个独立于硬件平台的运行环境,使得Java程序可以在任何安装了JVM...

    浅谈JAVA垃圾回收机制.pdf

    Java 中的垃圾回收机制通过各种算法和垃圾回收器来对可回收对象进行回收,提高了 Java 语言的开发效率和代码的可靠性。 在 Java 中,垃圾回收机制的引入可以避免代码运行时,由于忘记释放对象而带来的内存泄漏问题...

Global site tag (gtag.js) - Google Analytics