黑马程序员技术交流社区

标题: 求解:一个小问题? [打印本页]

作者: 刘经鹏    时间: 2012-12-25 18:59
标题: 求解:一个小问题?
关于内存的区域划分,各区域的特点(含垃圾回收机制),请高手详细介绍下?
作者: Rancho_Gump    时间: 2012-12-25 19:43
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分成很多个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。Java虚拟机规范中把Java虚拟机所管理的内存划分为以下几个区域。
   
    一、程序计数器(Program Counter Register)
   
    程序计数器是一块较小的内存空间,它的作用是当前所执行的字节码的行号指示器。它是线程私有的,即各个线程都有独立的程序计数器。
   
    如果线程正在 执行一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是native方法,则这个计数器是空(undefined)。
   
    此内存区域是唯一的一个不会抛出OutOfMemoryError异常的区域。
   
    二、Java虚拟机栈(Java Virtual Machine Stacks)
   
    我们可能经常听到说Java内存分为堆内存和栈内存,其实这个说法中的栈内存是指Java虚拟机栈中的局部变量表部分。
   
    Java虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行时都会同时创建一个栈帧(Stack Frame),用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直到执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。Java虚拟机栈也是线程私有的,生命周期也线程相同。
   
    局部变量表存放的类型包括以下三种:
   
    1、编译期可知的基本数据类型:boolean、byte、char、short、int、float、long、double共8 种类型;
   
    2、对象引用:即reference类型,它存放的是一个指向堆中对象起始地址的引用指针,或一个代表对象的句柄或者其他与此对象相关的位置,根据虚拟机的不同实现而不同;
   
    3、returnAddress类型:存放指向一条字节码指令的地址;
   
    局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量表空间是完全确定了的,方法在运行期间不会改变局部变量表的大小。
   
    Java虚拟机栈会抛出两种异常:
   
    1、OutOfMemoryError异常:如果虚拟本可以动态扩展,当扩展时无法申请到足够的内存时抛出;
   
    2、StackOverflowError异常:如果线程请求的栈深度大于虚拟机所允许的深度时抛出;
   
    三、本地方法栈(Native Method Stacks)
   
    本地方法栈与虚拟机栈的作用相似,它是为虚拟机在执行native方法时服务,而虚拟机栈是为虚拟机执行Java方法服务。此内存区域也会抛出OutOfMemoryError异常和StackOverflowError异常。
   
    四、Java堆(Java Heap)
   
    Java堆是用于存放对象实例和数组。它是Java虚拟机管理的内存中最大的一块,被所有线程共享,在虚拟机启动时创建,也是垃圾收集器管理的要区域,几乎所有的对象实例都在这里分配内存。
   
    如果垃圾收集器采用的是分代收集它还,它还可以细分为新生代和老年代,再细致一点的有Enden空间、From Survivor空间、To Survivor空间等。
   
    Java堆可以处理物理上不连续的内存空间中,只要逻辑上连续即可。在实现时既可以实现丰固定大小的,也可以是可扩展的。如果是可扩展的,可以通过-Xms和-Xmx来指定最小和最大值,如果-Xms和-Xmx的值相等,则相当于不可扩展了。如果堆中没有内存可完成实例分配,此内存区域会抛出OutOfMemoryError异常。
   
    五、方法区
   
    方法区用于存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它是堆的一个逻辑部分,是各个线程共享的内存区域。如果是sun的HotSpot虚拟机,它也叫做永久代(Permanent Generation),如果方法区无法满足内存分配需求时,会抛出OutOfMemoryError异常。
   
    方法区中的运行时常量池(RuntimeConstant Pool),用于存放编译期生成的各种字面量和符号引用,它在类加载后存放到运行时常量池中。
   
    运行时常量池具有动态性,即常量不一定只在编译期产生,在运行期间也可能将新的常量存入池中,比如String类的intern()方法。
   
    六、直接内存(DirectMemory)
   
    它不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。比如在JDK1.4中新加入的NIO类,有一种基于通道与缓冲区的I/O方式,它可以使用native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。所以直接内存不会受到Java堆大小的限制,但会受到本机总内存的大小及处理器寻址空间的限制。它也会抛出OutOfMemoryError异常。
--------------------------------------------------------------------------------------------------
本人百度的结果,挺详细的,共同学习.
作者: 刘经鹏    时间: 2012-12-25 22:11
感谢分享,还有关于各区域的垃圾回收机制的介绍吗?
作者: 李培根    时间: 2012-12-26 04:11
刘经鹏 发表于 2012-12-25 22:11
感谢分享,还有关于各区域的垃圾回收机制的介绍吗?

垃圾回收机制不用太关注吧,只要知道什么时候变垃圾就好了。
对内存中对象没有实体指向时就变成垃圾。
栈内存方法结束就变垃圾




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2