这一部分在我看来讲的都是概念上的东西,实际上各个JVM的结构都不一样,实现很复杂,而且随着时间发展各个区域也不是一成不变的,事实上所谓的区域、结构划分完全是在逻辑上人为划分的,如果有兴趣的话可以查看《深入理解Java虚拟机》以及JVM的说明文档去查看具体内容。

“Java的内存”,即Java的运行时数据区,也就是Java的内存结构(Java Structure),但注意区分Java的内存模型(Java Memory Model,JMM),JMM现在我还没仔细去研究过,有兴趣的同学可以自行百度查看下,如果以后有时间,我也会研究,然后记下自己的理解。

Java的内存结构,可以分为以下几个部分:堆、栈、非堆以及其他。

1.堆:存放Java对象,所有的对象(包括数组,但Class对象除外)数据实际存放地方。堆是程序级别,每一个Java程序共享一个堆(所以存在多线程访问堆内存同步问题)。

2.栈:存的是引用(如果是基本类型,则存的是值),引用(直接或间接)指向堆中的对象。栈是线程级别,每一个线程有各自的栈。栈又分为两种,一是Java方法栈,一是本地方法栈(有的JVM这两者是合在一起的,不过这里还是讨论逻辑上)。另外,每个线程都有各自的程序计数器,也是栈格式的。

(另外,比较疑惑的是,栈是不是堆得一部分呢?用的时候从堆分配出来?还是一开始就分出一部分内存用于栈?新开线程从这一部分分配出来?不过不管怎么样,逻辑上可以看成两个部分)

3.非堆:方法区、常量池、静态变量、即时编译后的代码等(貌似jdk1.7常量池又放在堆中了,逻辑上还是单独拿出来好了),堆与非堆的区别是,堆是供给程序使用,而非堆是供给JVM使用的。(严格来说,栈也是非堆?),因为主要是方法区,这部分又常常被称为方法区,又因为这部分数据不会(应该说很少会)被GC(GC,垃圾对象回收,详见下一节),所以也称为永久代。

jdk8好像有把非堆全部移除的,取而代之的是一个叫元空间,不过这里不详细谈,有兴趣可以参考:Java 8: 从永久代(PermGen)到元空间(Metaspace)(炎黄)

4.其他:存放JVM本身代码。

5.另外说一点,直接内存(OS管理的内存一部分),这不是JVM内存的一部分,但在NIO中,引入了一种基于通道和缓冲区的IO方式,Java程序可以通过本地方法的形式直接分配这部分内存,以DirectByteBuffer对象作为引用,间接操作使用。

其具体结构图可以大体概括如下:

堆内存又分为:Old区+ Young区,Young区又划分为:Eden + Survivor,Survivor又划分为:From + To (From 、To 大小相等,这些大小都能手动设置),如下图所示:

0).为什么要这样划分?因为性能,每次GC可以按照不同区域GC,加快垃圾回收速度。不过也因此,如果有更好的GC算法,可能划分就不一样了。

1).新建的对象存放到Eden区,From/To存放经过一次及以上GC的对象,若经过n次(可设置,通常为0,这里的0意思是GC检查时是0移到From/To区,并且该值+1,不是0移到Old区),对象每次GC若能存活(每次GC,Eden区清空),移到From/To区,以后都是从From到To再到From跳来跳去,经过n次,变成“老对象”就会被移到Old区。

2).堆是共享空间,每次分配空间要加锁。但是有的JVM会为每个线程分配一个TLAB空间,这样就不用加锁(不过这种仅适用于小对象,大的还是直接分配在堆上)。

3).堆在物理上是可以分散的,只要在逻辑上连续的就可以,大小可以是固定的,也可以是可扩展的,主流的JVM采用的都是可扩展的,可以用-Xmx -Xms控制(详见JVM优化一节)。

4).Old区、Eden区的内存并不一定会被填满,相反,一般情况下,不可能被填满,而是达到一定的值就会启动GC(详见GC一节)。

0.程序计数器

又称PC寄存器(Program Counter Register),较小的一块内存,用来存放下一条指令(当前指令正在执行引擎中执行,在指令寄存器中?),如果当前执行的是本地方法,则PC寄存器不存任何信息(本地方法执行不通过Java的执行引擎)。另外,如何去取下一条指令就是PC寄存器的工作,像跳转、分支、循环、异常处理等都依赖于PC寄存器来完成。PC寄存器是唯一一个不会有OutOfMemoryError情况的区域。

1.Java方法栈

程序主要的工作地方,每个线程私有,生命周期同线程,另外,一个方法其实就是一个帧,主线程main启动,就会创建主线程的栈,同时将第一个帧(main方法)压入栈中,每创建一个方法就将一个新的帧压入,帧用于存储局部变量表、操作栈、动态链接等信息。方法结束,帧出栈,相对应的内存消除(包括局部变量指向的堆中的对象也会被下一次GC)。当调用本地方法,则工作转到本地栈。

当进入一个方法的时候,其所需要的内存大小是确定的了,不会再改变。如果线程申请的栈深度大于JVM所允许的深度,则会抛出栈溢出StackOverflowError;若是JVM栈可以动态扩展(栈不是固定长度,需要的时候可以自动增加深度,当前JVM基本上都支持这种),但是当扩展时无法申请得到足够的内存同样会抛出OutOfMemoryError异常错误。

另外说一点,局部变量中的对象引用并一定是直接指向实例对象,具体的实现是由JVM决定的,主要有两种实现方式:

(1).直接指向实例对象,由实例对象提供指向对应Class对象的引用。

(2).指向一个句柄池(Java堆开辟出来的),句柄池存放着实例对象地址以及对应Class对象地址。

具体实现及优缺点,可参考《深入理解Java虚拟机》一书。

2.本地方法栈

用于本地方法调用,其他的同Java方法栈,所以有的JVM把两者合二为一。

非堆

也是程序共享区域,从这一点可以看出,JVM规范把他描述为堆的逻辑一部分是有一定的道理,虽然它有个非堆(Non Heap)名称。主要用来存储加载的类的信息、常量、静态变量等,有的称为这一部分为永久代,是因为GC不会处理这一部分,但有的JVM的GC算法也是会涉及到这个部分的(JVM规范对这一点并没有作要求),毕竟这一部分也会出现内存溢出异常的可能,比如,过多的加载类。

类的信息:包括所有类相关的信息:类变量、类字段、类的方法(包括静态方法和非静态方法,具体包括方法的修饰词、返回类型、参数列表等等)、类常量等,这一部分的实际结构很复杂,有兴趣的可以自行查阅。

总结:

0.一句话:栈线程私有,存放局部变量;堆程序共享,存放对象实例数据;非堆主要存放类信息(Class对象)。这是Java内存最主要的三块内存,而直接内存,如果没用到NIO是不会操作到的。

1.数据存放地方

局部变量:栈中,包括基本类型(存放的是值)、对象引用、返回地址;

类变量:方法区(非堆),类变量算是类信息一部分;

字符串和基本类型常量:常量池(事实上,常量池已被放到堆中,不过我们姑且将常量池单独在逻辑上拿出来);

Class对象:方法区(非堆);

new对象:引用放到栈中,对象数据放在堆中;

这些存放地方可能因为Java不断发展改变而不一样,但是逻辑上大概是这个意思,还有细节地方可能还有所不同(比如Eden可能还存放其他信息),如果想追究具体是什么情况的话,可以查看最新的jdk说明文档。

本节主要讲的是JVM运行时数据区,JVM内存各个区域的划分以及作用。

(3) Java内存结构相关推荐

  1. Java内存结构与垃圾回收机制算法分析

    什么是HotSpot VM 提起HotSpot VM,相信所有Java程序员都知道,它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机. 但不一定所有人都知道的是, ...

  2. JAVA内存结构解析

    原文链接:http://tryenough.com/java-memory-structure 更多:http://tryenough.com/type-android Java内存结构大体示意图: ...

  3. java 虚拟机 Java内存结构 JVM垃圾回收机制算法

    什么是HotSpot VM 提起HotSpot VM,相信所有Java程序员都知道,它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机. 但不一定所有人都知道的是, ...

  4. Java内存模型和Java内存结构精读

    以前看过很多遍JVM相关知识的文章,无非都是直接来张图片开搞,一来就甩张图片上来,这是方法区,这是堆,这是线程独享的一堆堆的概念,看得真的是头大,死记硬背也记不下来,更别说理解了. 最近一段时间在看j ...

  5. 【Java千问】你了解Java内存结构么(Java7、8、9内存结构的区别)

    Java内存结构是每个java程序员必须掌握理解的,这是Java的核心基础,对我们编写代码特别是并发编程时有很大帮助.由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是 ...

  6. 1、Java 内存结构

    1.Java 内存结构 1.1.Java 内存模型 堆 由线程共享,存放 new 出来的对象,是垃圾回收器的主要工作区域. 栈 线程私有,分为 Java 虚拟机栈和本地方法栈,存放局部变量表.操作栈. ...

  7. Java架构学习(十二)java内存结构新生代老年代JVM参数调优堆内存参数配置解决堆栈溢出

    JVM参数调优与垃圾回收机制 一.java内存结构 Java内存模型:是多线程里面的,jmm与线程可见性有关 Java内存结构:是JVM虚拟机存储空间. Java内存结构图 Java内存机构分为:方法 ...

  8. Java内存结构与Java内存模型

    Java内存结构.内存模型.对象模型这几个概念经常会被混为一谈.理论知识容易忘写下来帮助记忆,方便以后查看. 1.Java内存结构 Java内存结构其实说的是JVM在运行时内存区域的划分,是根据Jav ...

  9. Java内存结构和模型

    jvm的体系结构分为五个结构.方法区,堆,虚拟机栈,本地方法区,程序计数器PC.其中方法区和堆是所有线程共享的,每一个线程都有一个程序计数器 a.寄存器:这个概念比较模棱两可,网上查了一下一种说法是J ...

  10. 快速带你分清java内存结构,java内存模型,java对象模型和jvm内存结构!

    现如今你是否有这样的感觉,无论生活还是学习,节奏都是非常的快,每天面对海量的知识信息,自己感觉都要hold不住了,每天打开微信公众号,是不是发现有几十条未读,无论是技术文章还是其他类型的文章,我们大多 ...

最新文章

  1. python学习第二课要点记录
  2. git tag 介绍
  3. Firefox火狐Flash插件卡死问题完美解决方法(转载)
  4. python 更新数据库历史_python 实现数据库中数据添加、查询与更新的示例代码
  5. php程序设计案例教程 程序题,PHP程序设计案例教程
  6. flask mysql项目模板渲染_Flask系列(二) 模板 templates
  7. 避免Gson使用时将一些字符自动转换为Unicode转义字符
  8. 威马董事长沈晖隔空喊话王兴:威马一定会是Top3之一
  9. 三天花三万!跟董事长女儿相亲却被骗财?世纪佳缘致歉杭州小吴并承诺赔偿...
  10. 用DataFormatString格式化GridView 【转】
  11. 怎么改mnist数据的标签_详解 MNIST 数据集
  12. python爬取贴吧网页信息
  13. java 实心圆,liststyletype实心圆小图标大小颜色属性设置
  14. aws saa 认证价值大吗?aws认证指的是什么?
  15. java excel 多列排序_java poi处理excel多sheet并实现排序
  16. leetcode877
  17. Fanuc发那科法兰克数据采集实战c#——CNC数控系统数据采集、西门子免授权数据采集方案
  18. 看看人家,才知道长期主义的好处!
  19. 老家的思杨,胖乎乎的思杨,又长大了一点的思杨。
  20. 做人的基本原则你具备几项(一)

热门文章

  1. day03_2_作业
  2. kafka 客户端连接测试问题
  3. 游戏耳机什么牌子音质好?音质超好的耳机推荐
  4. 将递归函数转换为非递归形式
  5. 2020年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题
  6. 巨杉数据库与京东云携手,共筑PaaS新生态
  7. 端口被占用的解决方法
  8. android智能音响,蜂巢智能音箱
  9. 数组操作 reverse()方法
  10. 链接oracle配置c3p0,C3P0配置连接数据库