初识 JAVA 堆

举报
SHQ5785 发表于 2023/06/17 09:59:06 2023/06/17
【摘要】 一、前言众所周知,在java中内存主要分为以下几类:寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制。栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)堆:存放所有new出来的对象。静态域:存放静态成员(static定义的)。常量池:存放字符串常量和基本类型常量(public...

一、前言

众所周知,在java中内存主要分为以下几类:

  1. 寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制。
  2. :存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
  3. :存放所有new出来的对象。
  4. 静态域:存放静态成员(static定义的)。
  5. 常量池:存放字符串常量和基本类型常量(public static final)。
  6. 非RAM存储:硬盘等永久存储空间

这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。

对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

在前期博文《JVM进阶(一):初识JAVA栈》中我们说到了栈,栈在内存中是连续的空间;保存一个个的栈帧,对应一次次方法的调用;还讲到了栈是保存对象的引用,那么对象存在哪里呢?

二、堆存储

我们来看看下面的一张图:
这里写图片描述
对象就存在图中的内存区域,在JVM中,那片区域叫做堆!

由上图可以看到堆的存储结构和栈是不同的,堆在内存中并不是一块连续的区域,堆是分散的(物理上分散,但逻辑上是连续的,这里大家好好体会一下);虚拟机通过栈中引用的指引在堆中找到所需要的对象。

在虚拟机遇到一条new指令的时候,经过一系列的操作过后,虚拟机就要为该新生对象分配内存空间了,那么问题来了,这么散,虚拟机要怎么知道如何分配呢?分配的方式有两种:指针碰撞空闲列表

指针碰撞是将内存逻辑上分为两边,一边是空闲的,一边是在用的,指针指向分界点,当需要分配内存的时候只要移动指针即可。但这种只适用于内存规整的情况下,也就是刚刚说的分两边。一般用在Serial,PaeNew等垃圾收集器中,也就是堆中的新生代中。

空闲列表说的就是在内存不规整的情况下,虚拟机必须维护一个列表,用于记录哪些内存是可用的,在需要进行分配的时候就从列表中找到一块足够大小的空间进行分配,并且更新列表。该方法适用于像CMS这种基于Mark-Sweep的垃圾收集器,适用于堆中的年老区

上两段都提到了垃圾收集器,也就是GC。写过java应用的都知道,java程序很少需要我们去自己释放资源,原因就在于这个GC机制了。

三、总结

  • 存放new创建的对象和数组;
  • 在运行时动态分配内存(比如 new()),较慢,但灵活;
  • 是不连续的内存区域,在发出申请的时候,会干嘛干嘛的。。。。
  • Java虚拟机的自动垃圾回收器GC来管理。

四、拓展阅读

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。