Java内存区域

来源:互联网 发布:阿里云网站监控平台 编辑:程序博客网 时间:2024/06/03 16:37

Java内存区域

Java在大多数情况下不需要程序员插手于内存管理,因此部分Java程序员不了解内存区域的分布。但事实上,如果一旦出现内存泄漏的问题,不了解Java内存区域分布便难以排查错误源

Java虚拟机运行时数据区

  • 方法区
  • 虚拟机栈
  • 本地方法栈
  • 程序计数器

方法区

方法区与堆一样,是属于线程共享的内存区域。在方法区中虚拟机会加载类的信息,常量,静态变量等数据。方法区还有其他别名——“Non-Heap”,在HotSpot中,也被称为”永久代“。方法区的大小限制于内存。在方法区,虽然在HostSpot中称为永久代,但其实并不等价。Java虚拟机可以选择在方法区不实现垃圾收集,虽然在方法区进行垃圾回收量较小,但还是必不可少的。
由上图也可看出,常量池也是方法区的一部分。常量池中的内容是类加载后存放到方法区的常量池中的。常量池中的信息并非是预置于Class文件中的内容,常量池具有动态性,最好的例子便是String的intern()。常量池属于方法区的一部分,所以常量池的大小限制于方法区的大小。

Java堆是Java虚拟机管理的内存最大的一块。和方法区一样也被线程所共享的。在堆中只存放对象。原先在Java虚拟机规范中描述的是所有的对象都在堆中分配内存空间,但后来随着JIT编译器的发展以及逃逸技术的成熟等,也并不是所有的对象都在堆中。因为堆中存放的是对象,所以堆是GC的重点管理对象。有时候堆也叫做”GC堆“。此处牵扯到GC的具体算法与区块分配,又是一个大话题便不再多加描述。

虚拟机栈

Java虚拟机栈和本地方法栈与程序计数器一起,都是每一个线程所独有的。随线程而生,随线程而灭。虚拟机栈描述的是Java方法执行的内存模型,每个方法执行的时候会创建一个Stack Frame(栈帧)。每一个栈帧存放的是局部变量表、操作栈,动态链接,方法出口等信息。
局部变量表存放了基本数据类型,对象引用(后期会解释)和returnAddress类型(指向一条字节码指令的地址)。

本地方法栈

本地方法栈和虚拟机栈差不多,只不过虚拟机栈为Java方法提供服务,而本地方法栈为Native方法服务。Native方法其实是Java中使用native声明的使用C/C++编写的遵循JNI的文件中的方法。因为区别不大,所以在HotSpot中将本地方法栈和虚拟机栈合二为一。

程序计数器

程序计数器占用很小的内存空间。程序计数器的主要作用是当前线程所执行的字节码的行号指示器。字节码解释器工作就是通过改变计数器的值来选取下一条需要执行的字节码指令,来完成分支跳转等。
多线程的时候每一个线程都有一个程序计数器,如此可以在切换线程的时候回到每个线程应该在的位置。值得一提的有两个点,如果当前执行方法是Native方法,则计数器为空。另外一个是程序计数器是唯一一个没有规定任何OutOfMemoryError情况的区域。