这里结合一段 java 代码的执行理解内存划分

  • 执行 javac 命令编译源代码为字节码
  • 执行 java 命令
    1. 创建 JVM,调用类加载子系统加载 class,将类的信息存入方法区
    2. 创建 main 线程,使用的内存区域是 JVM 虚拟机栈,开始执行 main 方法代码
    3. 如果遇到了未见过的类,会继续触发类加载过程,同样会存入方法区
    4. 需要创建对象,会使用内存来存储对象
    5. 不再使用的对象,会由垃圾回收器在内存不足时回收其内存
    6. 调用方法时,方法内的局部变量、方法参数所使用的是 JVM 虚拟机栈中的栈帧内存
    7. 调用方法时,先要到方法区获得到该方法的字节码指令,由解释器将字节码指令解释为机器码执行
    8. 调用方法时,会将要执行的指令行号读到程序计数器,这样当发生了线程切换,恢复时就可以从中断的位置继续
    9. 对于非 java 实现(Native)的方法调用,使用内存称为本地方法栈
    10. 对于热点方法调用,或者频繁的循环代码,由 JIT 即时编译器将这些代码编译成机器码缓存,提高执行性能

说明:

  • 对于 Oracle 的 Hotspot 虚拟机实现,不区分虚拟机栈和本地方法栈

程序计数器:

线程私有的(每个线程都有一个自己的程序计数器), 是一个指针. 代码运行, 执行命令。而每个命令都是有行号的,会使用程序计数器来记录命令执行到多少行了,记录代码执行的位置

Java 虚拟机栈:

线程私有的(每个线程都有一个自己的 Java 虚拟机栈). 一个方法运行, 就会给这个方法创建一个栈帧, 栈帧入栈执行代码, 执行完毕之后出栈(弹栈)存引用变量,基本数据类型

本地方法栈:

线程私有的(每个线程都有一个自己的本地方法栈), 和 Java 虚拟机栈类似, Java 虚拟机栈加载的是普通方法,本地方法加载的是 native 修饰的方法。

native:在 java 中有用 native 修饰的,表示这个方法不是 java 原生的。

堆:

线程共享的(所有的线程共享一份)。存放对象的,new 的对象都存储在这个区域。还有就是常量池。

元空间:

存储.class 信息, 类的信息,方法的定义,静态变量等。而常量池放到堆里存储JDK1.8 和 JDK1.7 的 jvm 内存最大的区别是, 在 1.8 中方法区是由元空间(元数据区)来实现的常量池。

1.8 不存在方法区,将方法区的实现给去掉了。而是在本地内存中,新加入元数据区(元空间)

补充

不会出现内存溢出的区域

  • – 程序计数器

会出现内存溢出的区域

  • 出现 OutOfMemoryError 的情况(内存不足)
    • 堆内存耗尽 – 对象越来越多,又一直在使用,不能被垃圾回收
    • 方法区内存耗尽 – 加载的类越来越多,很多框架都会在运行期间动态产生新的类
    • JVM虚拟机栈累积 – 每个线程最多会占用 1 M 内存,线程个数越来越多,而又长时间运行不销毁时;一个线程在计算时所需要用到栈大小 > 配置允许最大的栈大小时;
  • 出现 StackOverflowError 的区域(栈溢出错误)
    • JVM 虚拟机栈,原因有方法递归调用未正确结束、反序列化 json 时循环引用

原文地址:http://www.cnblogs.com/Azureblue/p/16818275.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性