Jvm基础知识(1) - Java内存区域
Jvm
可以说是Java语言跨平台的基。当然Jvm
有好处也有坏处,好处就是我们Java程序员不用关心何时回收内存,跨平台编程等。坏处就是这导致我们Java程序员面临一些底层问题时无从下手,所以Jvm
的知识可以说是我们Java程序员必备的基础之一。先贴一张Jvm
的运行时数据区,借鉴了周志明老师的《深入理解Java虚拟机》:
运行时数据区
- 程序计数器(
Program Counter Register
) - Java虚拟机栈(
Java Virtua Machine Stack
) - 本地方法栈(
Native Method Stack
) - Java堆(
Java Heap
) - 方法区(
Method Area
) - 运行时常量池(
Runtime Constant Pool
) - 直接内存(
Direct Memory
)
程序计数器
程序计数器是线程私有的,它可以看成当前线程所执行的字节码的行号指示器,它是运行时区域唯一不会抛出OutOfMemoryError
的区域。
Java虚拟机栈
Java虚拟机栈也是线程私有的,它的生命周期和线程相同。它在运行时可能抛出StackOverflowError
和OutOfMemoryError
。
本地方法栈
本地方法栈是线程私有的,和Java虚拟栈不同的地方在于:Java虚拟栈执行的是Java方法,本地方法栈执行的是虚拟机所提供的native
方法。它在运行时可能抛出StackOverflowError
和OutOfMemoryError
。
Java堆
Java堆是Java运行时数据区中最大的一块区域,它存在的目的就是放置程序运行时的对象。所以它也是GC回收的重点区域,所以也叫做GC堆。按照GC的回收特性,它被分为了新生代和老年代,这个在后面的博客中会介绍,这里暂不展开。它在运行时可能抛出OutOfMemoryError
。
方法区
方法区存放着已经被加载完毕的类信息、常量、静态变量等,所以它也是全局唯一的,这个也符合我们平时的认知。为了和堆区分开,它也有一个名字叫做非堆。在这里我们要区分出来,方法区不是永久代,Hotspot的GC收集器在收集方法区的垃圾的时候采用的是永久代的算法,而在jdk1.8
中方法区改为由元空间实现。它在运行时可能抛出OutOfMemoryError
。
运行时常量池
运行时常量池存放着javac
编译器生成的各种字面量与符号引用,在jdk1.7
之前,所有的常量池存在于方法区中;在jdk1.7
之后,字符常量池被单独转移到了堆中,剩下的常量池依旧在方法区中。
直接内存
直接内存是为了方便我们的Java程序做I/O
操作所添加进去的。仔细想一想,我们在使用IO流读取计算机的文件的时候,首先是Java程序调用虚拟机提供的native方法做IO操作,然后再是native方法请求操作系统,显然这是十分费时费力的,所以添加了直接内存。它在运行时也会抛出OutOfMemoryError
。