<正则吃饺子>:关于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对慢速内存的访问。
*
*/
} }
这只是从网络上整理的一部分,还需要不断的学习总结。
<正则吃饺子>:关于java中对内存部分的简单总结整理的更多相关文章
- <正则吃饺子>:关于java中垃圾回收技术的简单学习总结
知识介绍来自网络,后面会根据继续学习进行补充和适当的修改,谢谢!原文地址:http://www.importnew.com/26821.html#comment-578355 java中的垃圾回收机制 ...
- Java中堆内存和栈内存详解2
Java中堆内存和栈内存详解 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...
- 关于Hash集合以及Java中的内存泄漏
<学习笔记>关于Hash集合以及Java中的内存泄漏 标签: 学习笔记内存泄露hash 2015-10-11 21:26 58人阅读 评论(0) 收藏 举报 分类: 学习笔记(5) 版 ...
- java中的内存一般分成几部分?
java中的内存被分成以下四部分: ①.代码区 ②.栈区 ③.堆区 ④.静态区域 栈区:由编译器自动分配释放,存放函数的参数值.局部变量的值等:具体方法执行结束后,系统自动释放JVM内存资源 ...
- (转)Java中使用正则表达式的一个简单例子及常用正则分享
转自:http://www.jb51.net/article/67724.htm 这篇文章主要介绍了Java中使用正则表达式的一个简单例子及常用正则分享,本文用一个验证Email的例子讲解JAVA中如 ...
- java中的内存溢出和内存泄漏
内存溢出:对于整个应用程序来说,JVM内存空间,已经没有多余的空间分配给新的对象.所以就发生内存溢出. 内存泄露:在应用的整个生命周期内,某个对象一直存在,且对象占用的内存空间越来越大,最终导致JVM ...
- Java SE之Java中堆内存和栈内存[转/摘]
[转/摘]1-3Java中堆内存和栈内存 注解:内存(Memory)即 内存储器,主存,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器(辅存)交换的数据. Java中把内存分为两种:栈 ...
- Java基础-Java中的内存分配与回收机制
Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.
- Java中的内存处理机制和final、static、final static总结
Java中的内存处理机制和final.static.final static总结 装载自:http://blog.csdn.net/wqthaha/article/details/20923579 ...
随机推荐
- android假设给TextView或EditText的email链接加下划线,并在点击在email连接上能够弹框显示
怎样把textview的一些文字加上背景色: Spannable str = new SpannableString("#fdsfdfsdfdsfd#"); Matcher mat ...
- EasyNVR无插件播放HLS/RTMP网页直播方案前端完善:监听表单变动
在上一篇博客中我们表述完了防止提交成功后多余操作提交的一个过程:其中的精髓在于ajax的触发事件的使用. 而这篇博客主要想说明一下如何实时的判断出表单是否发生变化. 问题表述: 在网页前端的开发过程中 ...
- idea创建普通java项目以及maven创建项目过程(转)
1. idea创建一个普通项目流程 http://blog.csdn.net/testcs_dn/article/details/52303941 2. idea创建maven项目流程 http:// ...
- java常用的基础容器
1 Vector and ArrayList 它们都是可以随机访问的.它们的区别是Vector是线程安全的,而ArrayList不是线程安全的. 2 HashMap的底层实现机制 2.1 底层数据结构 ...
- Error524 源站处理超时 Error 524: A timeout occurred
https://su.baidu.com/helps/index.html#/4/5a61e4b5b34f697f13234a5b Error524 源站处理超时 更新时间:2018-01-19 20 ...
- Kubernetes TensorFlow 默认 特定 集群管理器
Our goal is to foster an ecosystem of components and tools that relieve the burden of running applic ...
- zendstudio 13.0
官网原版下载 http://downloads.zend.com/studio-eclipse/13.0.0/ZendStudio-13.0.0-win32.win32.x86.exe 破解补丁: 链 ...
- 80端口未被占用,apache无法启动,命令行运行httpd.exe提示文档内容有错
Apache无法启动,端口被占用的可能性比较大,所以建议大家还是先换端口试试,这个网上说的比较多,具体可参见http://www.cnblogs.com/zdan68/p/3855636.html. ...
- 【shell】shuf命令,随机排序
shuf命令主要用来对输入的每一行进行随机排序输出,我们可以利用这个属性,实现在几个文件中随机读取一个的功能 如下,zls.txt文件有三行,我们想要随机从中读取一行. 可以看到,每次读取顺序都不一样 ...
- before-request , after-request
1 . flask的中间件 1)@app.before_request # 请求进入视图函数之前,类似于django中间件的request_process 2)@app.after_reque ...