跳转至

Java内存管理

约 682 个字 预计阅读时间 2 分钟

  • Java虚拟机(JVM)在运行时,会把内存划分为几个不同的逻辑区域,主要的内存区域可以分为三大块:栈(Stack)、堆(Heap) 和 方法区/元空间(Method Area/Metaspace)

  • 与C++类似,存放局部变量,以及引用数据类型(不是对象本身,而是它的引用地址

  • 堆是JVM管理的最大的一块内存区域,它的主要目的是存放对象实例。

  • 堆的特点是:所有线程共享同一个堆,因此在多线程访问堆中对象时需要考虑线程安全问题。堆也是垃圾回收器(Garbage Collector, GC) 主要工作的区域。

存储在堆里的变量:

  • 所有通过 new 关键字创建的对象实例:

  • 成员变量 / 实例变量 (Instance Variables):定义在类中、但在方法之外、没有 static 修饰的变量。这些变量是对象的一部分,所以它们跟随着其所属的对象一起存储在堆中。

  • 数组 (Arrays):数组在Java中也被视为对象,因此数组本身(包括其存储空间)也是在堆上分配的。

方法区/元空间

  • 方法区/元空间的核心设计目的,就是为了存放这些与具体实例无关的描述“类”本身信息的“蓝图”和“模板”
  1. 存放类的“元信息” (Store Metadata)

    • 这是最根本的目的。JVM需要一个地方来存储从 .class 文件中加载出来的所有结构化信息。这个地方就是方法区。通过将这份“蓝图”只存一份在方法区,所有根据这个蓝图创建出来的对象实例(都在堆中)都可以共享这份定义,极大地节约了内存。
  2. 实现数据共享与效率 (Enable Sharing and Efficiency)

    • 静态成员static 变量和 static 方法是属于类的,而不是属于任何一个对象的。将它们存放在方法区,可以保证它们只有一份,被所有对象实例共享

    • 常量池:通过运行时常量池(包括字符串常量池),可以复用大量的字面量(如字符串"Hello"),避免在堆中创建成千上万个内容相同的对象。

  3. 支持Java的动态特性(反射)(Support Dynamic Features like Reflection)

    • Java强大的反射机制,允许程序在运行时检查和操作类本身。例如,您可以通过Car.class获取到Car类的所有方法和字段。这些信息是从哪里来的呢?正是从方法区中存储的类元信息里读取的。没有方法区这样一个集中的“档案馆”,Java的反射就无从谈起。