java-内存划分

JVM(虚拟机)内存的划分

Java程序在运行时都要开辟空间,任何软件在运行时都要在内存中开辟空间,Java虚拟机运行时也是要开辟空间的。JVM运行时在内存中开辟一片内存区域,启动时在自己的内存区域中进行更细致的划分,因为虚拟机中每一片内存处理的方式都不同,所以要单独进行管理。

JVM内存的划分有五片:

  • 寄存器
  • 本地方法区
  • 方法区
  •  栈内存
  •  堆内存

寄存器:

  • 这是速度最快的存储场所,因为寄存器位于处理器内部,这一点和其他的存储媒介都不一样。不过寄存器个数是有限的
  • 在内存中的寄存器区域是由编译器根据需要来分配的。我们程序开发人员不能够通过代码来控制这个寄存器的分配

本地方法区:

  • 在本地方法栈中执行非java语言编写的代码,例如C或者C++

方法区:

  • 方法区在虚拟机启动时创建,也是一块所有线程共享的内存区域,它用于存储已被虚拟机加载的类的信息,常量,静态变量,及时编译器编译后的代码数据
  • 又叫静态区,跟堆一样,被所有的线程共享;方法区包含所有的class和static变量;方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量

栈内存和堆内存

  • 栈(Stack):Java中一个线程一个栈区,每一个栈中的元素都是私有的,不被其他栈所访问。栈有后进先出的特点,栈中的数据大小与生存期都是确定的,缺乏灵活性,但是,存取速度比堆要快,仅次于CPU中的寄存器,另外栈中的数据是共享的。在Java中,所有的基本数据类型和引用变量(对象引用)都在栈中存储,栈中数据的生存空间一般在当前的scopes内,也就是“{}”的部分,比如:函数的参数值,局部变量等,是自动清除的

 

  • 堆(Heap):Java中只有一个堆,被所有线程共享。堆中的数据没有先后顺序(逻辑上连续就好),堆中的数据不需要事先告诉编译器它的生存期,可以动态的分配内存的大小(动态的申请内存空间),也就是这样导致了存取速度慢。不再使用的数据由Java中的垃圾回收机制自动回收。在Java中由new创建出来的对象都是在堆中的,当垃圾回收机制检测到某对象未被引用时,则自动销毁该对象。

解释

  • 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用

 

  • 堆内存用来存放由new创建的对象和数组

 

  • 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量(引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象)

 

  • 引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器回收

 

  • 栈内存存储的是局部变量而堆内存存储的是实体
  • 栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短
  • 栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收

案例

如上图:

  • new一个Person对象时会将new出来的对象信息放在堆内存中
  • 生成的堆内存地址会和引用变量per一起存放在栈内存中
  • 当我们执行 per.name = "张三"; 时就会通过引用变量per找到堆内存的这个Person对象并修改name属性。当我们执行 per.age = 18; 也是相同道理
  • 假设我们执行 per = null;这时栈内存中的引用变per将失去堆内存地址,但这时堆内存不会被处理,需要等待垃圾回收来处理
  • 还有另外一种情况就是假设 Person per = new Person(); 是在if中的,但代码已经走完这个判断。这种情况下栈内存中的引用变量会直接被回收(栈内存超过作用域了),这时堆内存不会被处理,需要等待垃圾回收来处理

注意事项

int m=2;
int n=2; 
  • 当定义的是基本数据类型时,这些字面值的数据,大小和生命周期皆可知;编译器首先处理 int m=2; 先是在栈中创建一个变量为m的引用,然后在栈中查找有没有值为2的地址,没有则在栈中开辟一个新的存放字面值为2的地址,然后将m指向2的地址。接着处理 int n=2; 在创建完n的引用变量之后,由于存在2这个数值,则将n指向2的地址。这样会出现(m==n)为true的情况,也就是m和n指向同一个地址

 

  • 当定义完m之后,修改m的值,即m=3(此时m会开辟一个新的存放字面值为3的地址),那么n不会发生改变,依然等于2

 

  • 与基本数据类型引用不同,当同时指向一个地址是对象的引用时,如果该对象的内部状态发生改变,则另一个指向此对象的引用也发生变化。与之相反

 

  • 静态变量:位于方法区
  • 实例变量:作为对象的一部分,保存在堆中
  • 临时变量:保存于栈中,栈随线程的创建而被分配
  • 栈内存中存放局部变量(基本数据类型和对象引用),而堆内存用于存放对象(实体)
  • 对于字符串而言,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中;如果是运行期(new出来的)才能确定的就存储在堆中

 

 

 

 

法不轻传,道不贱卖,师不顺路,医不叩门,千金不传无义子,万才不渡忘恩人。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值