学习札记:JVM的内存布局

为什么要学习内存管理机制?
Java相对于C和C++ 而言,不需要为每个新建的对象去书写delete/free 代码,因为Java把这些管理交给了虚拟机。虽然不用写那么多代码,但是一旦出现内存泄露或溢出等问题则很难排查,所以我们首先要了解虚拟机内存中有哪些内容,各有什么作用,熟悉了JVM的工作原理才能更加得心应手地解决问题。


很多人都喜欢把内存分为两大类:堆内存(Heap)和栈内存(Stack),
堆是内存数据区,负责存储管理实例;
栈是内存指令区,存储基本数据类型,指令代码,常量,对象的引用地址等。

但是这种分法过为粗略,Java内存区域实际上比这复杂得多。
而我,则更为喜欢这样一种分法:线程共享区和线程独有区。
所有的线程共享内容为:堆空间和方法区。
线程独有的内容为:程序计数器、虚拟机栈空间和本地方法栈空间


了解了Java虚拟机内存分布有哪些区域,那么接下来我们再来了解每个区域里都是什么内容,理解各个内容所能发挥的作用吧。
线程共享区:
堆空间(Java Heap):Java堆在虚拟机启动时创建,唯一的目的就是负责存储对象实例。为什么要先说它呢?因为它是内存管理中最大的一部分。
同时,Java堆是垃圾收集管理的主战场,也就是GC堆(Garbage Collected Heap)。从内存回收方面来说,Java堆可以细分为:新生代和老年代;再细致一点的划分有:From Survivor 空间、To Survivor 空间、Eden 空间等。

方法区(Method Area):它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。方法区作为堆空间的一个逻辑部分与Java堆一样,是可以实现线程共享的内存区域。

简单地了解了线程共享区,下面我们再来聊聊线程独有区
程序计数器(Program Counter Register):它可以看作是当前线程所执行的字节码的行号指示器。如果线程正在执行的是Java方法,则程序计数器记录的是正在执行的虚拟机字节码指令的地址;如果线程正在执行的是Native方法,则程序计数器记录的值为空(Underfined

Java虚拟机栈(Java Virtual Machine Stacks):虚拟机描述的是Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame,它是方法运行时的基础数据结构)用于操作数栈、存储局部变量表、动态链接、方法出口等信息。每个方法从调用到执行完成就是一个栈帧在虚拟机栈中的入栈和出栈。

本地方法栈(Native Method Stack):它与虚拟机栈相似,但是虚拟机栈执行的是Java方法服务,而本地方法栈执行的是Native方法服务。有的虚拟机(Sun HotSpot)直接把本地方法栈和虚拟机栈合二为一。

了解完了内存布局及每个部分的作用,接下来我们谈谈我们平时碰到的堆栈溢出(StackOverFlowError)和内存溢出(OutOfMemoryError)异常都可能是哪里抛出的吧!
Java堆所在的内存区域是固定大小的,也可以是可扩展的。但是如果对堆中内存还没有全部完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。
当方法区无法满足内存分配需求时,将会抛出OutOfMemoryError 异常。
虚拟机栈中,如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出StackOverFlowError 异常;如果虚拟机栈可以动态扩展,当扩展时无法申请到足够内存时就会抛出OutOfMemoryError 异常。
本地方法栈与虚拟机一样,也会抛出堆栈溢出和内存溢出的异常。
而程序计数器是内存区域中唯一一个没有规定任何OutOfMemoryError 异常情况的区域。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值