Java内存区域与内存溢出异常——运行时数据区域

来源:互联网 发布:网络打鱼游戏赌博案件 编辑:程序博客网 时间:2024/05/18 01:50
  1. 程序计数器
    • 它是一块较小的内存空间,可以看做是当前线程所执行的字节码的行好指示器。
    • 字节码解释器就是通过它的值来选取下一条需要执行的字节码指令。
    • 每条线程都有一个独立的程序计数器,从而保证线程切换后,各条线程计数器之间互不影响。
    • 如果线程正在执行的是java方法,那么它会记录正在执行的虚拟机字节码的指令地址;如果现在执行的Native的方法,那么计数器的值是空的。
  2. Java虚拟机栈
    • 栈是线程私有的,生命周期与线程相同。
    • 它用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
    • 局部变量表存放了编译期间可知的各种基本数据类型、对象引用以及returnAddress。
    • 局部变量表所需的内存空间在编译期间就能完成分配,在方法运行期间不会改变局部变量表的大小。
    • 如果线程请求的深度大于虚拟机锁允许的深度,会抛StackOverflowError;如果虚拟机栈可以动态扩展,如果扩展无法申请到足够的空间,就会跑出OutOfMemoryError。
  3. 本地方法栈
    • 本地方法栈与虚拟机栈所发挥的作用是非常相似的,它为Native方法服务。
  4. Java堆
    • 堆被所有线程共享,它的唯一目的就是存放对象实例。
    • 所有的对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展与逃逸分析技术的成熟,并不是所有对象都分配在堆上,也能在栈里。
    • 是垃圾收集器管理的主要区域,可以细分为新生代和老年代(Eden空间、From Survivor空间、To Survivor空间等)。
    • 从内存分配的角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区。
    • 无论如何划分,存储的对象都是对象实例,进一步划分是为了更好的回收内存。
    • 堆在物理上不需要连续,只要在逻辑上连续即可。
  5. 方法区
    • 方法区跟堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类、常亮、静态变量、及时编译器编译后的代码等数据。
    • 可以选择不实现垃圾收集。这区域内存回收的主要目标是针对常量池的回收和对类型的卸载。
  6. 运行时常量池
    • 运行时常量池是方法区的一部分。
    • Class常量池用于存放编译期生成的各种字面量和符号引用。
    • 运行时常量池可以在运行期间将新的常量放入池中。
  7. 直接内存
    • 它是java虚拟机以外的内存区域,我们可以使用Native函数库直接分配对外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样可以避免Java堆和Native堆中来回复制数据。
0 0
原创粉丝点击