学习笔记之Java内存区域

前言

对于Java程序员来说,JVM的自动内存管理机制,让我们很舒服。不用像C++那样,为每一个new操作(开辟内存)去写对应的delete/free操作(回收释放内存)。但是呢,JVM也不是万能的,Java程序中,还是会出现内存泄漏、内存溢出方面的问题,而一旦出现了这类问题,如果我们不了解JVM是如何使用内存的话,那么排错就很难了。所以下面让我们来看一下Java的内存区域吧。
JVM在执行Java程序的过程中,会把它管理的内存划分成若干个数据区域,而且JDK 1.8之后和其之前的版本又略有不同。这一点有些地方比较明晰,有些地方又让人很纠结。我们可以先看看下面两张图。
图片来源:https://snailclimb.top/JavaGuide/#/docs/java/jvm/Java%E5%86%85%E5%AD%98%E5%8C%BA%E5%9F%9F
图片来源:https://snailclimb.top/JavaGuide/#/docs/java/jvm/Java%E5%86%85%E5%AD%98%E5%8C%BA%E5%9F%9F

程序计数器

它是线程私有的。为什么它是线程私有的呢?这是由它所要做的事所决定的。程序计数器可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变程序计数器的值来选取下一条需要执行的字节码指令。分支、循环、跳转、异常处理和线程恢复都要依赖程序计数器的功能。所以,为了让线程切换后,能恢复到正确的执行位置,每个线程都要有一个独立的程序计数器,这些程序计数器之间互不影响,故为线程私有的。

虚拟机栈

提到虚拟机栈,那肯定得想到Java方法了。虚拟机栈是线程私有的,它描述的是Java方法执行时候的内存模型。每次方法调用的数据都是通过栈传递的。Java虚拟机栈由一个个栈帧组成,每个栈帧中含有:局部变量表、操作数栈、动态链接、方法出口等信息。
局部变量表主要存放了编译器可知的基本数据类型(byte、char、short、int、long、float、double、boolean)以及对象引用(reference,它不是对象本身,而是一个指向对象起始地址的引用指针或者是指向一个代表对象的句柄)。
虚拟机栈中,其实主要就是拿来保存栈帧的。线程中的每一个方法调用,都会有一个对应的栈帧会被压入虚拟机栈里。而每一个方法调用结束或返回后(return语句或抛出异常都能导致方法调用的返回),该栈帧就会从虚拟机栈中弹出。
当然,虚拟机栈是会出现StackOverFlowError或是OutOfMemoryError的。你写一个没有终止条件的递归方法跑起来就知道了。至于出现哪种错误是看虚拟机栈的内存大小允不允许动态扩展。当不允许动态扩展的时候,若当前线程请求的栈深度超过了当前Java虚拟机栈的最大深度后,就会抛出StackOverFlowError。若允许动态扩展,当线程一直请求栈深度,请求到无法再动态扩展时,就会报OOM了。

本地方法栈

本地方法栈和虚拟机栈差不太多,只不过是服务对象不同而已。虚拟机栈为JVM执行Java方法服务,而本地方法栈为JVM执行Native方法服务。在HotSpot虚拟机中,本地方法栈和虚拟机栈合二为一了。

堆是JVM所管理的内存中最大的一块区域。堆是所有线程共享的,在虚拟机启动时创建。堆是用来存放对象实例的,几乎所有的对象实例以及数组都在堆里分配内存。
堆也是垃圾收集器所管理的主要区域,因此也称为GC堆。从垃圾回收的角度,现在的垃圾收集器一般都采用分代垃圾收集算法,所以堆还可以细分为新生代和老年代,然后新生代又可以细分为Eden空间、From Survivor空间以及To Survivor空间。分这么复杂也不是没事找事,而是为了能更好地回收内存和分配内存。
堆内存的细分。  图片来源:https://snailclimb.top/JavaGuide/#/docs/java/jvm/Java%E5%86%85%E5%AD%98%E5%8C%BA%E5%9F%9F
大部分情况,对象会首先在Eden区域分配。在一次新生代垃圾回收后,如果对象还存活,就会进入S0区或S1区 ,进入哪个区是不固定的,但是是有这么个道理:进去Eden区的某对象在第一次垃圾回收后还存活,假设进入了S0区,也恭喜它年龄变为了1岁,在下一次垃圾回收的时候,若它还存活,就会进入S1区,变为2岁,又在下一次垃圾回收的时候,它又存活了,这样它又进入了S0区,这时它3岁了。就这样,循环往复,当它的年龄达到了你设置的阈值,一般来说是15岁,它就能晋升到老年代了,也就是最右边的tentired区。

方法区

方法区也是各个线程共享的内存区域。它用于存储已被JVM加载的类信息、常量、静态变量以及即时编译器(JIT)编译后的热点代码等数据。静态方法和实例方法都是在方法区里的,其实就是方法表里。对于实例方法可以自己想想,不会每生成一个对象就有一种实例方法的。

从上面两张图对比可以看到,在JDK 1.8之后,方法区没了,取而代之的是元空间。这其实无所谓,就是换了种实现方式。《Java虚拟机规范》只是规定了有方法区这么个概念,以及它具有什么作用,但是并没有规定具体怎么去实现它。这就像Java中接口和具体实现类一样。在JVM里,JDK 1.8之前,方法区是由永久代去实现的。而在JDK 1.8之后,方法区就由元空间去实现了。而且还有一个关键的地方,JDK 1.8之后元空间直接放到了直接内存里。这是什么概念呢?之前用永久代实现时,永久代有一个JVM本身设置的固定大小的上限,而元空间因为是在直接内存里,它的上限就是本机可用的物理内存大小,基本不会出现OOM(Out Of Memory),当然,如果出现了,你机子估计也要卡掉了。

运行时常量池

这个地方是真的有点乱,网上各种说法,真假难辨。最好能自己coding下,找出真理。运行时常量池是方法区的一部分。class文件中,除了有类的版本、字段、方法、接口等描述信息外,还有用于存放编译期生成的各种字面量和符号引用的常量池信息。
有一种说法是,JDK 1.7之后,字符串常量池从方法区中移了出来,放到堆里去了。而其他的常量池仍然在方法区里,当然JDK 1.8之后,方法区指的是元空间。关于字符串常量池,能写的东西比较多,而且很烦,这里就不讲了,之后有空再补充。
图片来源:https://blog.csdn.net/wangbiao007/article/details/78545189

直接内存

直接内存并不是JVM运行时数据区的一部分,也不算虚拟机规范里定义的内存区域,但是这部分内存也被频繁地使用,更别说JDK 1.8之后,方法区以元空间的实现方式搬家到这儿来了。
JDK 1.4之后引入了 NIO(New Input/Output)类,引入了一种基于通道(Channel)和缓存区(Buffer)的I/O方式,它可以通过Native函数库分配堆外内存(就是这个直接内存),然后通过存储在堆里的DirectByteBuffer对象作为这块内存的引用进行操作。
直接内存的分配不会收到Java堆内存的限制。但是,必然会受到本机物理内存的影响以及处理器寻址空间的限制。

最后

Java内存区域的理解还是很重要的,这里主要作下笔记,再加入了点个人理解,有什么错的地方可以提出一起探讨,仅记录用。
图片来源:
1.https://snailclimb.top/JavaGuide/#/docs/java/jvm/Java%E5%86%85%E5%AD%98%E5%8C%BA%E5%9F%9F
2.https://blog.csdn.net/wangbiao007/article/details/78545189

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值