寄存器:
最快的存储区,位于处理器内部,但是数量极其有限。所以寄存器根据需求进行自动分配,无法直接人为控制
堆区:
位于RAM当中,一种通用的内存池。其中存放的数据由JVM自动进行管理。
jvm只有一个堆区(heap)被所有线程共享,只存放对象本身。又称动态内存分配,当需要一个对象时,使用new写一行代码,当执行这行代码时,会自动在堆里进行存储分配。使用完毕之后,会在垃圾回收器空闲的时候尽心那个回收。
1. Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,是虚拟机所管理的内存中最大的一块。此内存区域的唯一目的就是【存放对象实例和数组】,几乎所有的对象实例和数组都在这里分配内存。
2. Java堆是垃圾收集器管理的主要区域,也称为GC 垃圾堆。后面会专门分析GC算法。
从内存回收的角度看,由于现在收集器基本都采用分代收集算法,所以Java堆可以细分为:新生代、老生代;
从内存分配的角度看,线程共享的Java堆可能划分出多个线程私有的分配缓冲区(TLAB);
不论如何划分,都与存放的内容无关,无论哪个区域,存储的仍然是对象实例和数组。
3. 如果在堆中没有内存完成实例分配,并且堆上也无法再扩展时,将会抛出OutOfMemoryError异常。
4. 内存泄露和内存溢出
内存泄露 : 指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存。即被分配的对象可达但已无用,可用内存越来越少。
内存溢出 : 指程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于老年代或永久代垃圾回收后,仍然无内存空间容纳新的Java对象的情况。
内存泄露是内存溢出的一种诱因,不是唯一因素。
栈区:
位于RAM当中,通过堆栈指针可以从处理器获得直接支持。堆栈指针向下移动,则分配新的内存;向上移动,则释放那些内存。这种存储方式速度仅次于寄存器。
用于存放对象引用和基本数据类型(注意没有String)
当方法被执行时,方法体内的局部变量(其中包括基础数据类型、对象的引用)都在栈上创建。
因为栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
使用完毕,立即回收。
静态存储区(方法区):
主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好,并且在程序整个运行期间都存在。
1. 方法区又被称为静态区,是程序中永远唯一的元素存储区域。和堆一样,是各个线程共享的内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
2. Java虚拟机规范对方法区的限制非常宽松,除了和Java堆一样 不需要连续的内存和可以选择固定大小或者可扩展之外,还可以选择不实现垃圾回收。
这区域的内存回收目标主要是针对常量池的回收和类型的卸载,一般而言,这个区域的内存回收比较难以令人满意,尤其是类型的回收,条件相当苛刻,但是这部分区域的内存回收确实是必要的。
3. 很多开发者更愿意把方法区称为“永久代”(Perm Gen)(Permanent Generation)「总是存放不会轻易改变的内容」。在目前已经发布的JDK 1.7 的HotSpot中,已经把原本放在永久代的字符串常量池移至堆中。
4. 运行时常量池(Runtime Constant Pool)是方法区的一部分。
栈与堆的区别:
存储数据类型:栈区存储基本数据变量(注意不包括String)和引用数据变量(通过new关键字创建的),堆内存用来存放所有由 new 创建的对象(包括该对象其中的所有成员变量)和数组
可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,这个特殊的变量就是我们上面说的引用变量。我们可以通过这个引用变量来访问堆中的对象或者数组。
存储速度:就存储速度而言,栈内存的存储分配与清理速度更快于堆,并且栈内存的存储速度仅次于直接位于处理器当中的寄存器。
灵活性:就灵活性而言,由于栈内存与堆内存存储机制的不同,堆内存灵活性更优于栈内存。灵活性:就灵活性而言,由于栈内存与堆内存存储机制的不同,堆内存灵活性更优于栈内存。
原文:https://www.cnblogs.com/alex-xyl/p/11298555.html