内存模型
Java内存区域
虚拟机运行时数据区如下图所示:

方法区:方法区又称为永生代(Permanent Generation)是线程共享的内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。当方法区内存溢出时报OOM:PermGen space。编译器生成的各种字节码和符号引用存放在运行时常量池中。
堆:Java堆是Java虚拟机所管理的内存中最大的一块,所有线程共享。此内存区域唯一的目的是存放对象实例。几乎所有的对象实例(非基础类型)都在这里分配内存。Java堆还可以细分为新生代和老年代,其中新生代又可以分为Eden空间、From Survior空间、To Survior空间,对应的默认比例是8:1:1。在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。
虚拟机栈:虚拟机栈是线程私有的,虚拟机栈描述的是java执行的内存模型,每个方法在执行的时候都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每个方法调用到执行的过程对应一个栈帧入栈到出栈的过程。
程序计数区:虚拟机处理多线程时,是通过轮流的切换线程,来获取cpu的执行机会的。在虚拟机执行程序的过程中,当线程执行到某一位置时,虚拟机将cpu的执行机会出让给了其他线程,此时原有线程的执行位置需要被记录下来,而新得到执行机会的线程,又需要提供上次执行的位置,以此来保证程序中的多个线程可以持续的并行的执行下去。程序计数器的作用就是将各个线程下次所执行的(字节码)行号(准确来说是指令的地址)记录下来,以保证其下次执行时可以正确的执行。程序计数器只记录字节码的行号,因此当线程执行本地方法(Native method)时,计数器的值是空。程序计数器所耗费的内存空间非常小,因此这个区域是不会抛出OutOfMemoryError错误的。
本地方法栈:与虚拟机栈的作用非常相似,只是虚拟机栈为虚拟机执行Java方法服务,本地方法栈则为虚拟机使用的Native方法服务。
虚拟机运行时数据区之外的内存叫直接内存(Direct Memory),当我们使用NIO来,会调用Native方法直接分配堆外内存,通过一个存储在java堆中的DirectByteBuffer对象被java程序使用。
网友评论