深入理解java虚拟机阅读小记

一、Java内存区域与内存溢出异常

     java虚拟机在运行java程序时将它所管理的内存区域划分为程序计数器、java虚拟机栈、本地方法栈、堆、方法区这几个运行时数据区。

          1.1、程序计数器:一块很小的内存,它的作用是当前线程正在执行字节码的行号指示器。(线程私有

      java虚拟机多线程是通过线程轮流切换执行处理器时间的方式实现的,任何一个确定时刻,一个处理器只会执行一个线程的某个指令,为了多个线程切换后能正确的执行,每个线程都需要一个程序计数器,各个线程的程序计数器互不影响,我们称之为线程私有

          1.2java虚拟机栈(线程私有):是描述java方法执行的内存模型,用于存放局部变量、操作栈、动态链接、方法出口等信息,会抛出StackOverflowErrorOutOfMemoryError异常。

          1.3、本地方法栈(线程私有):和java虚拟机栈很像,只不过它是为执行Native方法服务,会抛出StackOverflowErrorOutOfMemoryError异常。

          1.4、堆(所有线程共享):唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存;它是垃圾收集器管理的主要区域,也称为GC堆,会抛出OutOfMemoryError异常。

          1.5、方法区(所有线程共享):存储类信息、常量、静态变量等(运行时常量池属于方法区的一部分),会抛出OutOfMemoryError异常。

     直接内存:在jdk1.4中新加入了NIONew Input/Output)类,引入了一种基于通道与缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。当本机内存不够时会抛出OutOfMemoryError异常。

     对象访问举例

[java] view plaincopy

1.  Object obj = new Object();  

假设这句代码出现在方法体中:其中“Object obj”这段语法定义将反映到虚拟机栈的本地变量表中,“new Object();”这部分将反映到java堆中形成一块存储改对象的内存区域,其次在堆中必须还需包含到能查到该对象类型数据(对象类型、父类型、实现的接口、方法等)地址信息,这些数据存放在方法区中。

 

二、垃圾收集器与内存分配策略

      垃圾收集(GC)主要针对堆、方法区进行内存回收,需要完成三件事:1.那些内存需要回收、2.什么时候回收、 3.如何回收

      判断对象是否存活算法:引用计数算法、根搜索算法

          1.引用计数算法:给对象添加一个引用计数器,引用该对象则计数器+1,取消引用则-1,如果计数器为零就认为对象已死,可回收(该方法无法解决对象间互相引用的问题)

[java] view plaincopy

1.  objA.instance = objB;   objB.instance = objA;  

          2.根搜索算法:通过一系列名为“GC Roots”的对象作为根节点,然后通过这些节点往下搜索,搜索经过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,可以认为对象已死,可回收。在java语言中,可作为GC Roots的对象包括以下几个方面:

              1.虚拟机栈中引用的对象

              2.方法区静态属性引用的对象

              3.方法区常量属性引用的对象

              4.本地栈中引用的对象

      引用:

              jdk1.2以前java中的引用定义:如果reference类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用

              jdk1.2以后对引用的概念进行了扩充:分为强引用、软引用、弱引用、虚引用

                  强引用:代码中普遍存在的”Object obj = new Object():”这类引用

                  软引用:描述一些还有用,但并非必须的对象,提供SoftReference类来实现软引用

                  弱引用:也是描述非必须对象的,提供WeakReference类来实现

                  虚引用:最弱的一种引用关系,提供PhantomRefercence类来实现

       方法区(永久代)垃圾收集主要回收两部分的内容:废弃常量和无用的类

                废弃常量:没有再被引用的常量

                废弃类:该类的所有实例都被回收、加载该类的ClassLoader已经被回收、该类对应的java.lang.Class对象没有在任何地方被引用,无法通过反射访问该类的方法

       垃圾收集算法:

                1.标记清除算法:算法分为标记和清除两个部分,先标记出所有需要回收的对象,然后统一回收被标记的对象。缺点:该算法标记和清除效率都不高,标记清除后会产生大量的不连续内存碎片,分配大对象时可能由于连续内存不够,而导致另一次垃圾回收操作。

                2.复制算法:将内存分为大小相等的两块,开始使用其中的一块,在垃圾回收时将存活的对象复制到另一块内存,然后一次清理掉第一块内存,这种算法的缺点是可使用内存减少了一半。

                3.标记整理算法:标记部分和标记清楚算法一样,然后将存活的对象向一端移动,最后清理掉在端边界外的对象。

                4.分代收集算法:根据对象的存活周期将内存分为几块,一般将java堆分为新生代和老年代,在新生代中每次垃圾收集时都有大量对象死去,少量存活使用复制算法,在老年代中对象存活率高,采用标记清理或标记整理算法。

        垃圾收集器:可以认为收集算法是内存回收的方法论,垃圾收集器则为具体实现。

    原文作者:java虚拟机
    原文地址: https://blog.csdn.net/w_y_loong/article/details/8197931
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞