前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA内存学习总结

JAVA内存学习总结

作者头像
Java架构师历程
发布2018-09-26 15:38:22
4050
发布2018-09-26 15:38:22
举报
文章被收录于专栏:Java架构师历程Java架构师历程

从最开始学习java的时候,老师就讲过,java主要分为堆和栈两个内存区域,随着不断的学习和深入,也对java的内存有了更细致的了解。本文是个人通过以前老师所讲知识、查看各位大牛的博客,总结而来,纯属个人学习总结体会,不喜勿喷。

java内存划分

这里写图片描述
这里写图片描述

如上图所示,java内存主要分五个部分:

  1. 方法区(Method Area):方法区是各个线程共享的区域,用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等。比如String str = “const”;const就会存放在常量池中,当String strC = new String(“const”).intern(); str==strC 返回true。intern()方法会去常量池找到const这个常量,没有则重新生成const常量放入常量池。这里字符串常量才存到方法区的常量池,其他8种基本数据类型是不存放在这里的。
  2. 堆(Heap)对于java程序员再熟悉不过了,几乎所有的对象实例和数组是在堆中分配内存,它是被所有线程贡献的一块内存区域。GC主要管理的也是这部分区域,关于GC相关的在后续再说。堆分为:新生代和老年代。新生代又分为:Eden区,From Survivor、To Survivor区,默认比例为 8:1:1。通过参数-Xmx -Xms控制,最大和最小一般保持一致,避免动态扩容以及每次GC后重新分配内存。此区域内存不够时,会发生OutOfMemoryError。具体堆内存还可以细分:
这里写图片描述
这里写图片描述

这里细分主要涉及到垃圾回收机制时,后面有GC的详细介绍;

  1. Java虚拟机栈(JVM Stack):一个线程的每个方法在执行的同时,都会创建一个栈帧(Statck Frame),栈帧中存储的有局部变量表、操作站、动态链接、方法出口等,当方法被调用时,栈帧在JVM栈中入栈,当方法执行完成时,栈帧出栈。 局部变量表中存储着方法的相关局部变量,包括各种基本数据类型,对象的引用,返回地址等。在局部变量表中,只有long和double类型会占 用2个局部变量空间(Slot,对于32位机器,一个Slot就是32个bit),其它都是1个Slot。需要注意的是,局部变量表是在编译时就已经确定 好的,方法运行所需要分配的空间在栈帧中是完全确定的,在方法的生命周期内都不会改变。 一般来说,一个Java的引用访问涉及到3个内存区域:JVM栈,堆,方法区。 以最简单的本地变量引用:Object obj = new Object()为例: Object obj表示一个本地引用,存储在JVM栈的本地变量表中,表示一个reference类型数据; new Object()作为实例对象数据存储在堆中; 堆中还记录了Object类的类型信息(接口、方法、field、对象类型等)的地址,这些地址所执行的数据存储在方法区中; 在Java虚拟机规范中,对于通过reference类型引用访问具体对象的方式并未做规定,目前主流的实现方式主要有两种: 1.通过句柄访问(图来自于《深入理解Java虚拟机:JVM高级特效与最佳实现》):
这里写图片描述
这里写图片描述

通过句柄访问的实现方式中,JVM堆中会专门有一块区域用来作为句柄池,存储相关句柄所执行的实例数据地址(包括在堆中地址和在方法区中的地址)。这种实现方法由于用句柄表示地址,因此十分稳定。 2.通过直接指针访问:(图来自于《深入理解Java虚拟机:JVM高级特效与最佳实现》)(一般学习java基础的时候,老师都是讲的这种)

这里写图片描述
这里写图片描述

通过直接指针访问的方式中,reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。这种方法最大的优势是速度快,在HotSpot虚拟机中用的就是这种方式。

  1. 本地方法栈(Native Method Statck):本地方法栈在作用,运行机制,异常类型等方面都与虚拟机栈相同,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。
  2. 程序计数器(Program Counter Register):程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。 每个程序计数器只用来记录一个线程的行号,所以它是线程私有(一个线程就有一个程序计数器)的。 如果程序执行的是一个Java方法,则计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是一个本地(native,由C语言编写 完成)方法,则计数器的值为Undefined,由于程序计数器只是记录当前指令地址,所以不存在内存溢出的情况,因此,程序计数器也是所有JVM内存区 域中唯一一个没有定义OutOfMemoryError的区域。

至此,就对java中内存有了一个详细的了解,对后面的垃圾回收机制和性能优化打下基础。

参考博文:

Java内存区域概述

优秀Java程序员必须了解的GC工作原理

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年10月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • java内存划分
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档