[TOC]
Java内存分配浅析
计算机存储结构
先来简单了解下计算机的存储结构,计算机采用三级存储结构:
- 高速缓冲存储器cache
- 主存储器
- 辅存储器
可看做两层:cache-主存,主存-辅存
细分的存储层次:
- CPU(寄存器)
- cache
- 内存(RAM)
- 硬盘(Hard Disk)
java数据类型
基本类型
8bit = 1Byte - byte, 8bit
- int, 32bit
- short, 16bit
- long, 64bit
- boolean, 16bit
- float, 32bit
- double, 64bit
- char, 16bit
引用类型
Array, String和对象,都位于堆中。
基本类型变量只在栈区占用一块内存,而引用类型变量要在栈区和堆区各占一块内存。
Java内存区域
java程序的运行在JVM中,运行时虚拟机会将它所管理的内存区域划分为若干不同的数据区域,这些区域都有各自的用途及创建销毁时间。
就速度来说,有如下关系:
寄存器 < 栈 < 堆 < 其他
寄存器(Register)
CPU内部元件,每个寄存器都有自己的名字,程序无法直接控制,高速读写速度。分为内部寄存器和外部寄存器。
内部寄存器也就是小小的存储单元。
可用来寻址或者计算
栈,堆
java将内存(RAM)分为栈内存和堆内存
栈(Stack)
存放基本类型的数据(如int,short,long,byte,boolean,float,double,char…)和引用类型的地址。引用类型本身存放在堆中。
当程序中定义一个变量时,就在栈中为变量分配一个内存空间,当变量超出作用域时,java会自动释放改变量的内存空间。
创建程序时候,JAVA编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性
堆(Heap)
存放由new创建的数组和对象,有java虚拟机的垃圾回收机制自动回收。当堆中的数组和对象在没有引用变量指向它们的时候,才会变为垃圾,然后在随后一个不确定的时间被回收,这也是java比较占内存的原因。
运行时数据区,运行过程中动态分配内存的。
java堆是所有线程所共享的一块内存区域,该区域的唯一目就是存放对象。可以处于物理上不连续的空间,逻辑上连续即可
java中的指针:栈中的引用变量指向堆中的变量
区别
栈:存取速度快,仅次于寄存器,栈数据可以共享。存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
堆:运行时动态分配,存取速度慢。
String类型存放
字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常 量池中,而有的是运行时才被创建.使用new关键字,存放在堆中。
详细内容请查看String解析一文
静态域(static storageb)
这里的“静态”是指“在固定的位置”。静态存储里存放程序运行时一直存在的数据。你可用关键字static来标识一个对象的特定元素是静态的。
常量池(constant pool)
常量池指在编译期被确定,并保存在已编译的.class文件中的一些数据,包括定义的基本常量数据,对象型(String及数组)和常量值(final)。
JVM必须为每个装载的类型维护一个常量池,常量池就是该类型所用到的常量的义序有序集合
在堆中分配出来的一块存储区域,存放储显式的String常量和基本类型常量(float、int等)。另外,可以存储不经常改变的东西(public static final)。常量池中的数据可以共享。
非RAM存储
硬盘等永久存储空间,存放一些数据完全存活于程序之外,它可以不受程序的任何控制,在程序没有运行时也可以存在。
堆栈溢出
堆溢出简单,循环创建对象即可
for(;;){ ArrayList list = new ArrayList(2000); }
栈溢出
实现栈溢出,需要调用递归public void test(){ this.test(); }
JVM堆栈设置
java –Xms128m //JVM占用最小内存 –Xmx512m //JVM占用最大内存 –XX:PermSize=64m //最小堆大小 –XX:MaxPermSize=128m //最大堆大小