Java把内存划分为两种:一种是堆内存,一种是栈内存
堆:主要用于储存实例化的对象、数组。由JVM动态分配内存空间。一个jvm只有一个堆内存,线程是可以共享数据的。
栈:主要用于储存局部变量和对象的引用变量,每个线程都有有一个独立的栈空间,所以线程之间不共享数据的。
在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈空间中分配。当在一段代码块定义一个变量时,java就在栈中为这个变量分配内存空间,当 超过变量的作用域后,java会自动释放掉该变量所分配的内存空间,该内存空间可以立即被另作他用。
堆内存用来存放由new创建的对象和数组,在堆中分配的内存,由java虚拟机的自动垃圾回收器来管理。
2、 栈和堆的共同点和优缺点
1、 栈(stack)与堆(heap)都是java用来在内存中存放数据的地方,java自动 管理堆和栈。
2、 栈的优势是,存取速度比较快,仅次于直接位于cpu中的寄存器,当缺点是,存放在栈中的数据大小和生存期必须是确定的,缺乏灵活性。栈数据也是可以共享的。
堆的优势是可以动态的分配内存大小,生存期也不必事先告诉编译器,java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于在运行时动态分配内存,存取速度较慢。
3、 Java中的数据类型有两种
一种是基本类型,共8中。这种类型的定义是通过 诸如int a = 3;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的示例,所以没有类的存在。如ing a=3; 这里的a是一个指向ing类型的引用,指向 3这个字面值。这些字面值得数据,由于大小可知,生存期可知,出于追求速度的原因,就存在于栈中。
栈有一个很重要的特性,就是存在栈中的数据可以共享。
假如同时定义int a = 3;int b = 3;
编译器会先处理int a = 3;首先会在栈中创建一个变量为 a的引用,然后查找字面值为3的地址,没找到的话,就开辟一个存放3这个字面值得地址,然后a指向3的地址。接着处理int b = 3;由于在栈中已经有3这个字面 值了,便将b直接指向3的地址,这样 就出现了a和b同时指向3的情况
需要注意的是,这种字面值的引用和类对象的引用不同,假定两个类 对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另外一个对象引用变量也即刻反映出这个变化。
字面值的引用中,其中a的值得变化不会影响到b的值。
另一种是包装类数据,如Integer、String、Double等将相应的基本数据类型包装起来的类。这些 类 数据全部存在于 堆中,java用new()语句来 显式地告诉编译器,在 运行时才根据需要动态创建,因此比较 灵活,但缺点是要占用更多的时间。
3、 Java堆和栈的区别
栈内存用来储存局部变量和方法的调用,堆内存用来储存java中的对象。无论成员变量、局部变量、还是类 变量,他们指向的对象都储存在堆内存中。
栈内存归属于单个线程,每个线程都会有一个栈内存,其储存的变量只能在其所属线程中可见。堆内存中的对象对所有的线程可见。堆内存中的对象可被所有的线程访问。
如果栈内存没有足够的 空间储存方法的调用和局部变量,jvm会抛出stackOverFlowError.
如果堆内存没有 足够的空间储存方法的调用和局部变量,jvm会抛出OutOfMemoryError。
栈内存 要远远小于堆内存,如果使用递归的话,栈内存很快就会 用完,如果没有及时跳出的话,会发生stackOverFlowError问题。
可以通过,-Xss设置栈内存的大小 ,-Xms可以设置堆内存的开始大小,-Xmx可以设置堆的最大值。
4、 JVM中的堆和栈
JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。 我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的. 从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。
每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程 共享.跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。