博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
<正则吃饺子>:关于java中对内存部分的简单总结整理
阅读量:6034 次
发布时间:2019-06-20

本文共 5190 字,大约阅读时间需要 17 分钟。

在项目和一些群讨论中,经常看到对内存的处理,但是,自己确是一知半解的,基于此,就把这部分的知识简单的整理了下,知识点来源于网络博文,也一一标明出处,谢谢。

 

package com.love.malinda.utils;/** * 关于 堆与栈 * Date 2017-1-13 * @author Aaron * */public class StackAndHeadStudy {	/*	 * ####相关博文介绍:	 * -- http://blog.csdn.net/shimiso/article/details/8595564  --讲解比较详细	 * 	 *-- java内存分配研究:http://www.blogjava.net/Jack2007/archive/2008/05/21/202018.html	 *	     *-- Java常量池详解之一道比较蛋疼的面试题:http://www.cnblogs.com/DreamSea/archive/2011/11/20/2256396.html	 *		 *-- jvm常量池:http://www.cnblogs.com/wenfeng762/archive/2011/08/14/2137820.html	 *		 *-- 深入Java核心 Java内存分配原理精讲:http://developer.51cto.com/art/201009/225071.htm	 * 	 * ####一个完整的java程序运行时涉及的主要内存区域:	 * 寄存器:jvm内部虚拟寄存器,存取速度非常快,程序不可控制。	 * 	 * 栈:保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,也就是 堆 中对象的引用(指针)。也可以用来保存加载方法时的帧。	 * 	 * 堆:用来存放动态产生的数据,比如 new 出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。	 * 	     因为同一个类的对象拥有各自的成员变量,存储在各自的 堆 中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。	 * 	 * 常量池:jvm为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型、String)和对其他类型、方法、字段的符号引用。	 * 		     池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在java的动态链接中起了核心的作用。	 * 		  常量池存在于 堆 中。	 * 	 * 代码段:用来存放从硬盘上读取的源程序代码。	 * 	 * 数据段:用来存放static定义的静态成员。	 * 		 * 相关:1.无论是普通类型的变量还是引用类型的变量(俗称实例),都可以作为局部变量,他们都可以出现在栈中。	 * 			只不过普通类型的变量在栈中直接保存它所对应的值,而引用类型的变量保存的是一个指向 堆 的指针,通过这个指针,就可以找到这个实例在堆中对应的对象。	 * 			因此,普通类型的变量只在 栈 中占用一块内存,而引用类型的变量要在 堆 和 栈 中各占一块内存。作为参数时,基本类型就直接传值,引用类型传指针。	 * 	 * 		2.分清 对象 和 实例。Class a = new Class(); 此时 a 叫 实例,而不能直接说是对象。实例在栈中,对象在 堆 中,操作实例实际上是通过实例的指针间接的操作对象。	 * 			多个实例可以指向同一个对象。	 * 	 * 		3.栈 和 堆 中的数据销毁并不是同步的。方法结束,栈中局部变量立即销毁,但是 堆 中的对象不一定销毁。	 * 			因为可能有其他的变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且不是马上销毁,要等垃圾回收扫描时才可以被销毁。	 * 	 * 		4.以上的栈 、堆、代码段、数据段等都是相对于应用程序而言。每一个应用程序都是对应唯一的一个jvm实例,每一个jvm实例都有自己的内存区域,互不影响。	 * 			并且这些内存区域是所有线程共享的。这里提到的 堆 和 栈 都是整体的概念,这些 堆 和 栈 还可以细分。  	 * 			 * 		5.类的成员变量在不同的对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。而 类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候,	 * 			该方法才被压入 栈,方法不使用,则不占用内存。	 * 			 * 		6.其他。常量池,维护了一个已加载类的常量。	 * 				 * 		基本类型 和 基本类型的包装类。两者区别:基本类型体现在程序中是普通变量,基本类型的包装类是 类,体现在程序中是引用变量。因此两者在内存中的存储位置不同。	 * 		 基本类型在栈中,而其包装类是在堆中。	 * 		注意:byte,short,char,int,long,boolean 的包装类都实现了常量池技术。String 类型也实现了常量池技术。但是 ,两种浮点类型的包装类(Float,Double)则没有实现。 	 * 				 */			public static void main(String[] args) {		//关于常量池对于基本类型的测试,这其实是一道面试题		int i = 40;		int i0 = 40;		Integer i1 = 40; 		Integer i2 = 40;		Integer i3 = 0;		Integer i4 = new Integer(40);		Integer i5 = new Integer(40);		Integer i6 = new Integer(0);		Double d1 = 1.0;		Double d2 = 1.0;				System.out.println("i=i0	" + (i == i0));		System.out.println("i1=i2	" + (i1 == i2));  //这种情况时候,需要注意一个问题 数字段  只能在 -128~127之间。具体说明参见下面的解释。		System.out.println("i1=i2+i3	" + (i1 == i2 + i3));		System.out.println("i4=i5	" + (i4 == i5));		System.out.println("i4=i5+i6	" + (i4 == i5 + i6));		System.out.println("d1=d2	" + (d1 == d2)); 				//补充 Integer 的一个知识点。		Integer a = 1 ; //自动装箱。没有自动装箱,就应该是 Integer a = new Integer(1);		int b = a ;//自动拆箱。没有自动拆箱,就应该是  int b = a.intValue();						//运行结果://		i=i0	true//		i1=i2	true//		i1=i2+i3	true//		i4=i5	false//		i4=i5+i6	true//		d1=d2	false		/** 相关分析:* 		1. i 和 i0 都是普通类型 int 的变量,所以数据直接存储在栈中。而 栈 有个很重要的特性:栈中的数据可以共享。当我们定义了一个 int i = 40;这时如果再定义一个* 			int i0 = 40; 这时就会自动检测是否已经有 40 这个数据,如果有,i0 会直接指向 i 的40,不会再添加新的40;* 		* 		2. i1 和 i2 都是integer这个包装类在栈中的引用(索引,类的实例在栈中存储)。Integer 实现了常量池技术,i1 和 i2 都是从常量池获取的,均指向同一个地址。因此相等。* 			但是但是但是,先说三遍。这里有个瑕疵(也不算瑕疵了,反正是不能一用百用,需要注意):如果是 Integer ii1 = 129; Integer ii2 = 129;  再比较时候,就有问题了,返回 false 。		* * 			注意:* 					java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存。* 					看 valueOf() 的源码中,( return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];),(取值范围是 -128~127)* 					两个都是大于 128 的,new Integer(xx)的对象都是在堆中。内存地址不对,就是false;小于128 的还是在常量池中,就是true。*		*		3. java的数学运算都是在栈中进行的。* 		* 		4. i4 和 i5 都是引用。是存储在栈中的指针,由于是new 出来的,对应于 在堆中不同的内存地址,对象不同。也就是返回false了。* 		5. 同上。* 		6. d1 和d2 都是引用类型,存储于栈中。但是 两个 浮点类型 都没有实现 常量池 技术,就相当于 Double d2 = new Double(1.0);   。内存地址不一样,返回 false 。* 		* 		补充:* 				1. 常量池技术,维护的常量仅仅是【-128至127】这个范围内的常量,如果常量值超过这个范围,就会从堆中创建对象,不再从常量池中取。* 					比如,把上边例子改成Integer i1 = 400; Integer i2 = 400;,很明显超过了127,无法从常量池获取常量,就要从堆中new新的Integer对象,这时i1和i2就不相等了。* * 				2. String类型也实现了常量池技术,但是稍微有点不同。String型是先检测常量池中有没有对应字符串,如果有,则取出来;如果没有,则把当前的添加进去。* * 				3.  内存分区的一些对比:待补充* * 				4. 缓存 概念及相关涉及点:(根据网络上的资料简单整理)* 								a. 缓存位于应用程序和物理数据源之间,用于临时存放复制数据的内存区域,目的是为了减少应用程序对物理数据源范围的次数,从而提高应用程序的运行性能。* 								b. 缓存是CPU的一部分,它存在于CPU中。* 								c. 缓存只是内存中少部分数据的复制品,所以CPU到缓存中找数据,可能会出现找不到的情况,这时它就会到内存中去找,不过CPU会把这部分数据复制到缓存中,方便下次查找。* 								d. 随着时间变化,缓存中的数据可能不会被频繁的被访问了,或者又有新的数据要被频繁访问,所以啊,需要经常通过一定的算法来更新需要的数据。* 								e. 了解一级缓存、二级缓存:* 										RAM (random access memory)随机存储记忆体 ,断电后数据信息消失,	相当于 电脑的 移动存储设备								* 									    分为  静态RAM(SRAM)  ,存储速度较快,现在使用的缓存一般为此,* 												 动态RAM(DRAM) ,存储速度比DRAM慢,现在使用的内存一般为此。* 										* 										由于静态RAM的使用成本较高(存储体积更大,价格更高),但为了提高系统性能和运行速度,可以通过增加 告诉动态RAM作为缓存。* 										* 										运行速度对比: 静态RAM > 高速动态RAM > 常规动态RAM* 										查找数据的顺序:》》》一级缓存 》》》二级缓存》》》内存*  																其中,静态RAM 称为 一级缓存,高速动态RAM 称为 二级缓存	 * 										一、二级缓存中的内容 都是内存中访问频率较高的内容的复制品(映射),存在的目的是为了减少 高速CPU对慢速内存的访问。* */										}}

 这只是从网络上整理的一部分,还需要不断的学习总结。

转载于:https://www.cnblogs.com/zhengzeze/p/6519760.html

你可能感兴趣的文章
HDU 2243 考研路茫茫——单词情结(自动机)
查看>>
Dubbo OPS工具——dubbo-admin & dubbo-monitor
查看>>
如何将OpenCV中的Mat类绑定为OpenGL中的纹理
查看>>
CutyCapt
查看>>
Dungeon Master ZOJ 1940【优先队列+广搜】
查看>>
解决https://localhost:1158/em 页面无法打开的问题
查看>>
[Cocoa]深入浅出Cocoa之Core Data(4)- 使用绑定
查看>>
原理:什么是Quadtrees?(转)
查看>>
记:返回方法参数的值(或多个值),
查看>>
Effective C++ 的52个条款列表
查看>>
c#读取ini文件
查看>>
一阶微分方程的求解
查看>>
其它 Helper
查看>>
监控利器Prometheus初探
查看>>
foreach遍历打印表格
查看>>
Oracle笔记(中) 多表查询
查看>>
Delphi 中的 XMLDocument 类详解(5) - 获取元素内容
查看>>
差异分析定位Ring 3保护模块
查看>>
2013年7月12日“修复 Migration 测试发现的 Bug”
查看>>
vim文本编辑器详解
查看>>