知道尾号怎么查全手机号码尾数哪个吉利

前不久为知笔记宣布收费,用不惯印象笔记和有道的我,便充了一年的会员,既然钱已经花了出去,就不能像以前一样,不懂得珍惜,刚好最近在重读《深入理解》,关于内存管理这块又多了一些收获,便记录下来,顺便整理成,还是毛主席教导的好:好记性不如烂笔头啊!
文中前部分简摘自周志华老师的
《深入理解java虚拟机》
,后部分为个人的一些验证和总结。
java中的引用
相对于C++,Java语言非常好的一点就是不需要我们手动管理内存,因为有一个像妈妈一样的虚垃圾回收器,每天默默地替我们清扫着房间的垃圾,无怨无悔。基本上所有的java员都知道有这么个默默无闻的妈妈,可是你真的了解她吗?
上面提到垃圾回收器替我们清扫垃圾,那么重要的一点来了,什么是垃圾?在现实中,没有用的东西就是垃圾,会被丢进垃圾桶,运到处理厂,掩埋或是焚烧。其实在java的世界里也是一样,无用即为垃圾,不过这里的垃圾全都是:对象。
什么叫无用,即没有人要用,在java里,无用即代表没有被引用,java里面操控对象全都是通过引用来进行的,For Example:Object o=new Object(),这里我们就创建了一个Object对象,并用一个引用o来引用这个对象,这样我们就可以通过o来操作这个Obejct了。
java里一共有四种引用:
这就是我们上面写的Obejct o=new Object(),只要强引用还存在,对象就不会被回收。
SoftReference,只有将发生内存溢出时,才会进行回收。
WeakReference,GC工作时,无论当前内存是否够用,一定会回收。
PhantomReference, 有这个引用和没有一样,因为通过引用拿到的一定是null,和弱引用一样,GC工作时一定会被回收,唯一的作用就是监听对象被GC回收,可以用来做GC监听器,监听虚拟机的每一次GC。
1.引用——计数法
即在对象头部增加一个计数器,每当对象被引用,内部的计数器就+1,当引用失效,计数器就-1。这样当垃圾回收时,就回收那些计数值为0的对象。
缺点:很难解决对象之间相互循环引用的问题。
2.标记——清除法
从堆栈和静态区出发,遍历所有引用,找出所有存活的对象。每当找到一个对象,就给它设置一个标记,这样它就不会被回收。
缺点:清除后会产生大量的不连续,这样对于将来大对象的内存分配是不利的,因为可能因为找不到连续的大块内存,不得不触发下一次gc。
3.复制——清除法
将可用空间分为两块A和B,每次只使用AB其中的一块,比如当A中内存已满的时候,就将A中所有存活的对象一次性复制到B中,然后清空整个A区。一般来说,98%的对象都是朝生夕死,所有没必要1:1的分配AB,所以一般会将内存划分为3块,一块较大的Eden区,两块较小的Survivor区。每次使用Eden和一块Survivor,GC时将存活对象移动到另一块Survivor中。但是一块Survivor可能容纳不下所有的存活对象,所以需要依赖另一块进行分配担保,只能将存活的一部分对象放入担保中,这就是内存的分配担保机制。
4.标记——整理法
这种方法的标记过程和标记清除算法一样,但是它解决了标记清除的问题。它的清扫过程不是直接进行的,而是先将所有存活对象都移动到一边,然后整个清扫那一边,这样就不存在内存空间不连续的问题了。
1.对象优先在新生代中分配
新生代分为Eden区和Survivor区,大小比例通常为8:1,新对象一般在Eden区进行分配,当Eden区已满时,虚拟机会发起一次GC,将Eden区还存活的对象移动至Survivor区,并一次性清扫Eden区。
大对象直接进入老年代
所谓的大对象是指需要大量连续内存空间的对象,比如说很长的或者数组。经常出现大对象容易导致内存还有不少空间时就要进行gc,以获取足够空间来存放它们。
长期存活的对象将进入老年代
如果对象在Eden区出生,并能够顺利熬过第一次gc,且能被Survivor区容纳的话,那么将被移动到Survivor区,并初始化年龄为1岁,以后每熬过一次gc,年龄就加一次,当年龄增加到一定程度(默认15),就会晋升到老年代中。
对于所有的对象总不能一刀切吧,每种算法都有其缺点和优点。所以一般会将对象划分为新生代和老年代,对于新生代这种朝生夕死的对象,用复制清除算法,并采用老年代进行担保。而对于老年代中生命力较为顽强的对象,采用复制清除是不合适的,因为需要巨大的空间来进行分配担保,所以一般会采用标记清除或者标记整理算法。
1.为什么新生代采用复制清除法?
新生代gc比较频繁、对象存活率低,用复制算法在回收时的效率会更高,也不会产生内存碎片。
2.为什么复制清除法需要两块Survivor区?
如果说只有一块Survivor区,那么会发生如下情况:
第一次GC:Eden区的存活对象移动到Survivor区;
第二次GC:Eden区和Survivor区都发生了GC,都会只有一部分对象存活,这时再将Eden区存活对象复制至Survivor区,因为Survior自身存活对象的不连续性,便会产生内存碎片。
如果有两块Survivor区(S1,S2)的话,情况就能好很多:
第一次GC:Eden区的存活对象移动到S1区,S2空闲;
第二次GC:Eden区和S1区都发生了GC,都会只有一部分对象存活,这时再将Eden和S1的存活对象复制至S2区,这时Eden和S1又会保持空闲,且S2中的空闲内存也是连续的。
GC日志分析
只学习理论是不够的,只会似懂非懂,绝知此事要躬行,下面我们就来通过实战分析一下垃圾回收器。
首先通过定时器每秒分配一个100M的大数组,并实时查看内存使用情况。
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
Runtime runtime = Runtime.getRuntime();
.out.print(&total:&+(runtime.totalMemory()/1024)+ &k\n&);
long free=runtime.freeMemory()/1024;
System.out.print(&free:& + free+ &k\n&);
if(free&102400){
System.out.print(&need gc&+&\n&);
byte[] a1 = new byte[100 * 1024 * 1024];
a1[1] = 1;
System.out.print(a1[1]+&\n&);
timer.schedule(task, );
下面来看看打印出的信息:
total:251392k
free:243527k
total:251392k
free:141127k
total:354304k
free:141639k
total:457216k
free:142151k
total:560128k
free:142663k
可见分配大对象时,虚拟机并不是频繁的gc,而是在不断的申请内存,totalMemory在不断变大。
下面在通过设置-XX:+PrintGCDetails来打印GC日志:
max:3728384k
total:2872832k
free:100166k
[GC (Allocation Failure) [PSYoungGen: 7864K-&480K(76288K)] 2772665K-&72832K), 0.0423481 secs] [Times: user=0.15 sys=0.01, real=0.05 secs]
[GC (Allocation Failure) [PSYoungGen: 480K-&448K(76288K)] 2765280K-&72832K), 0.0365171 secs] [Times: user=0.11 sys=0.00, real=0.03 secs]
[Full GC (Allocation Failure) [PSYoungGen: 448K-&0K(76288K)] [ParOldGen: 2764808K-&423K(79360K)] 2765256K-&423K(155648K), [Metaspace: 3019K-&8K)], 0.4096268 secs] [Times: user=0.04 sys=0.37, real=0.41 secs]
max:3728384k
total:258560k
free:154426k
通过GC日志可知,当连续空间不够时,分配对象失败,然后会针对新生代发起一次minorGC,内存使用从7864k降低到了480k,这样还剩余75808k,但是还不够分配102400k的数组,所以接下来又因为分配失败发起一次minorGC,但是这次却没有回收到太多垃圾,那么怎么办,只能往老年代分配了。现在我们来计算一下老年代还有多少空间:
old = total - young = 2872832 - 74k
oldFree = old - oldUsed = 2796544 - 736k
老年代也只剩余31736k的空间,根本不够分配102400k的数组,这时就出现了内存分配担保失败,也就导致了下一步的发生:Full GC。
Full GC一般都是担保失败才出现,表明这次GC发生了Stop The World,会对所有年代进行回收。可以看见,第三次GC后,新生代对象被全部回收,老年代的大对象也基本被回收,但是这次GC后totalMemory变小了,从 2872832k 降低为 155648k 了。这时无论是新生代还是老年代都不够分配数组了,所以只能申请更大的内存空间了,分配数组后totalMemory又升至 258560k了。
当手动停止程序后,又打印出了新的堆内存日志:
PSYoungGen
total 76288K, used 3058K [0xab00, 0x0000)
eden space 65536K, 4% used [0xab000076adfca70,0xeb00000)
from space 10752K, 0% used [0x000,0x0000)
space 10752K, 0% used [0xeb000,0x0000)
total 799744K, used 717223K [0x00, 0xab00000)
object space 799744K, 89% used [0x00006ebc69d08,0xd00000)
used 3029K, capacity 4500K, committed 4864K, reserved 1056768K
class space
used 331K, capacity 388K, committed 512K, reserved 1048576K
从上面可以看出,新生代中eden区只使用了4%的空间,而老年代却使用了89%的空间,这也印证了大对象都在老年代中进行分配。
只看GC日志的话,很多信息无法得到,那么最好的办法就是实时监控内存了。
接下来对上面的程序进行一些小改变,通过一个类变量对分配的数组加以强引用,这样保证数组不会被gc回收掉,然后我们就可以来监控JVM了。
1.输入jps -l,打印出进程pid
WangXiandengde-Pro:test wangxiandeng$ jps -l
66083 com.intellij.rt.execution.application.AppMain
15875 com.xk72.charles.macosx.Main
66082 org.jetbrains.jps.cmdline.Launcher
66084 sun.tools.jps.Jps
AppMain即为当前运行的进程pid,为66083。
2.利用jstat来监控该进程
WangXiandengdeMacBook-Pro:test wangxiandeng$ jstat -gc
................
80.0 771.4
可见,100m的数组全都是直接在老年代中直接分配,最后一行可以看出,此时内存已经不够分配,于是发生了3次minorGC,2次FullGC,但是因为老年代中的数组全被强引用了,导致无法回收。
[GC (Allocation Failure) [PSYoungGen: 7864K-&512K(76288K)] 2772665K-&72832K), 0.0433492 secs] [Times: user=0.16 sys=0.01, real=0.04 secs]
[GC (Allocation Failure) [PSYoungGen: 512K-&496K(76288K)] 2765320K-&72832K), 0.0422158 secs] [Times: user=0.11 sys=0.00, real=0.04 secs]
[Full GC (Allocation Failure) [PSYoungGen: 496K-&0K(76288K)] [ParOldGen: 2764808K-&96544K)] 2765304K-&72832K), [Metaspace: 3069K-&8K)], 0.0720605 secs] [Times: user=0.04 sys=0.07, real=0.08 secs]
[GC (Allocation Failure) [PSYoungGen: 0K-&0K(76288K)] 2765263K-&72832K), 0.0388848 secs] [Times: user=0.15 sys=0.00, real=0.03 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K-&0K(76288K)] [ParOldGen: 2765263K-&96544K)] 2765263K-&72832K), [Metaspace: 3069K-&8K)], 0.0291437 secs] [Times: user=0.04 sys=0.00, real=0.03 secs]
Exception in thread &Timer-0& java.lang.OutOfMemoryError: Java heap space
at com.wangxiandeng.test.Test$1.run(Test.java:30)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
这时虽然totalMemory远未达到maxMemeory,但是因为老年代能够分配到的空间有限,即老年代已经不能申请到新的空间了,而这些大数组又无法放入新生代中,所以只能内存溢出了。
虽然了解java不需要我们手动管理内存,但是了解这方面还是很有必要的,一是可以避免写出导致频繁GC、内存泄漏和溢出的代码,二是可以对虚拟机进行调优,虽然一般调优都是端同学的事,但是今天却看到了维术同学的一篇新
《性能优化之虚拟机调优》
,很是佩服。
(如有错误,欢迎指正!)每天三分钟,知晓天下事,视频、语音、文字综合版任您挑!微信搜索fgzadmin关注或点击标题下方可以快速关注。
原创不易,认可价值,动手指点并转发,就是最好的支持与肯定。淘宝特约店址:http://goldengame.
深夜十点,陪你读书。
慢工出细活
由于中、美、俄三国自2008年后基本上长期上演“三国杀”(昨天文章《原创丨中美俄世纪三国杀,谁是百年长跑冠军
其实这是个有奖活动贴。n其实这是个有奖活动贴。n其实这是个有奖活动贴。
思考者正在阅读原创丨三次世界大战亚洲开打,美国推演靠谱吗?原创丨央行连出两大招,有何深意?微历史丨张学良为啥
美国总统奥巴马日在接受媒体采访时表示,2011年对利比亚局势的干涉,是其总统生涯中做出的最
我们都知道,美国软实力很厉害,在过去很多年都一直掌控者国际话语权,他们可以提着民主、自由、人权的大棒满世界乱
思考者正在阅读原创丨重大变革,我们的世界都将逃不过被TA重塑!原创丨中美黄岩岛较量,谁是最后赢家?原创丨你射君,已阅读到文档的结尾了呢~~
JAVA内存机制及内存调整、监控文档文档,内存,监控,内存监控,Java,内存调整,java,java吧
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
JAVA内存机制及内存调整、监控文档
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口}

我要回帖

更多关于 手机号码尾数哪个吉利 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信