• <正则吃饺子>:关于java中对内存部分的简单总结整理


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

    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对慢速内存的访问。
    * 
    */									
    	}
    
    }
    

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

  • 相关阅读:
    UIImagePickerController从拍照、图库、相册获取图片
    swift2.0 UIImagePickerController 拍照 相册 录像
    UIImagePickerController拍照与摄像
    iOS 从相机或相册获取图片并裁剪
    Android播放音频的两种方式
    UICollectionView的基本使用
    UIImageView圆角,自适应图片宽高比例,图片拉伸,缩放比例和图片缩微图
    UIView属性clipsTobounds的应用
    iOS开发UI篇—CALayer简介
    chrome插件演示,经js转让chrome api清除浏览器缓存
  • 原文地址:https://www.cnblogs.com/zhengzeze/p/6519760.html
Copyright © 2020-2023  润新知