<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>王 晨纯 | 酷 壳 - CoolShell</title>
	<atom:link href="https://coolshell.cn/articles/author/hesey/feed" rel="self" type="application/rss+xml" />
	<link>https://coolshell.cn</link>
	<description>享受编程和技术所带来的快乐 - Coding Your Ambition</description>
	<lastBuildDate>Mon, 26 May 2014 06:37:54 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2</generator>
	<item>
		<title>「我只是认真」聊聊工匠情怀</title>
		<link>https://coolshell.cn/articles/11629.html</link>
					<comments>https://coolshell.cn/articles/11629.html#comments</comments>
		
		<dc:creator><![CDATA[王 晨纯]]></dc:creator>
		<pubDate>Mon, 26 May 2014 03:20:55 +0000</pubDate>
				<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=11629</guid>

					<description><![CDATA[<p>（感谢网友 @Hesey小纯纯 投稿  博客 &#124;　原文链接） 老罗的Smartisan T1手机发布会很多人应该都看了，发布会的最后老罗凝视着自己的工匠自画像，...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/11629.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/11629.html">「我只是认真」聊聊工匠情怀</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><strong style="color: #555555;">（感谢网友 <a style="color: #2970a6;" href="http://weibo.com/tbmujian" target="_blank">@Hesey小纯纯</a> 投稿  <a style="color: #2970a6;" href="http://blog.hesey.net/" target="_blank">博客</a> |　<a style="color: #2970a6;" href="http://blog.hesey.net/2014/05/im-just-conscientious-talking-about-feelings-of-artisans.html" target="_blank">原文链接</a>）</strong></p>
<p>老罗的Smartisan T1手机发布会很多人应该都看了，发布会的最后老罗凝视着自己的工匠自画像，半晌没说话，随后转过身，慢慢离开舞台，屏幕下方只留下一句话：</p>
<p style="padding-left: 30px;"><strong>我不是为了输赢，我就是认真。</strong></p>
<p>这一瞬间让我想起93年「狮城舌战」的主角蒋昌建，在「人性本善还是人性本恶」的总结陈词最后，以顾城的名句，「黑夜给了我黑色的眼睛，我却用它寻找光明」，把整个辩论赛的氛围推向高潮。</p>
<p>而老罗的这句话，和这句话背后的工匠背景，却以另外一种<strong>无声的却震人心魄的力量</strong>，敲打着每一个在场的，或是观看着整个发布会的观众的心绪。</p>
<p>「工匠情怀」，我深有体会，就像我在 <a href="http://blog.hesey.net/2014/05/gc-oriented-java-programming.html" target="_blank">面向GC的Java编程</a> 一文中所提到的：</p>
<p style="padding-left: 30px;"><strong>优秀程序员的价值，不在于其所掌握的几招屠龙之术，而是在细节中见真著。</strong></p>
<p style="padding-left: 30px;"><strong>如果我们可以一次把事情做对，并且做好，在允许的范围内尽可能追求卓越，为什么不去做呢？</strong></p>
<p>追求卓越，追求完美，追求细节的极致。小时候看到那些修表匠，握着一个小螺丝刀，或是看着电工，用烙铁沾着锡和松香，在那一小寸的世界里，把坏了的地方修好，那种专注的眼神，觉得很厉害。</p>
<p>现在再去回想那些工匠工作的场景，越发觉得钦佩。在我老家有一家刻章的店，在我上幼儿园的时候就已经在那开了很多年了。前段时间需要刻一个章，发现那家店还在，于是走进去，门口坐着一个老人，我确实记不得当年是不是他，不过看这岁数八九不离十。我以前在别的地方刻的章，都是在电脑里设计完图案后，激光刻蚀。但那次老人却是用的手刻，我着实惊呆了。只看他拿出一块红色的印底，右手持着刻刀，开始一下一下地刻着。虽然老人连话都不怎么说得清了，但是工作时那专注的神情，和精湛的手艺，以及最后成品那比机器更完美的效果，着实让我心里非常动容。</p>
<p><span id="more-11629"></span></p>
<h4>一、技术人的执着</h4>
<p>我见过很多人，也见过很多程序员，都有如此的「工匠情怀」。</p>
<p>做产品需求评审，有的人善于快速提供技术解决方案，在最短的时间内解决问题。</p>
<p>但我见过的很多牛人，他们除了能在脑海里最快地形成方案原型，并且更深入地考虑各种细节点，最终能给出一个更趋于完善的技术方案。</p>
<p>在他们身上，我看到了<strong>对这项职业的自我尊重，对自我价值的追求，也有对「卓越」的理解和渴求</strong>。</p>
<p>《精通正则表达式》的译者余晟老师写过他和正则表达式的 <a href="http://www.luanxiang.org/blog/archives/1717.html" target="_blank">缘起</a> 。只是因为项目经理让他「多用Google，查查正则表达式的资料」，余老师打开了正则的大门，读完了英文原版的《Mastering Regular Expression》，如今成为了国内最了解正则表达式的人之一。</p>
<p>看完那篇文章其实我想起了我的实习经历。那时候我刚去公司两三天，有一天我老板找我让我研究一下如何用Java里的MappedByteBuffer做文件内存映射来读取大文件。尽管我们当时要处理的文件很大，以我在学校编码的经验看，用普通的Reader也是可以很好地解决的。</p>
<p>于是我说，「这个其实用Reader也能做，更简单一些，没那么麻烦。」</p>
<p>老板反问我，「什么叫没那么麻烦，这是一个做技术的人的态度吗？」</p>
<p>那几天我花了很多时间，去从Linux一直到JVM，去了解什么是内存映射，底层原理是什么，和其它技术的比较、优缺点，并和其它几种读文件的技术做了性能对比。</p>
<p>虽然最后项目没有采用这个方案，但是那句反问直到现在一直在我脑海里，时时地提醒我：「<strong>做技术的人，对待技术，应该拥有什么样的态度？</strong>」</p>
<p>所以其实我很感谢我的老板，以前他教我们这些新人优秀的职场习惯，有一条是每天的邮件必须没有未读数，即便是不需要阅读的邮件，也要一键置为已读，不要留一个未读的数字在那。现在想起来，有点像iOS App右上角那个提醒数的角标，有些强迫症的人怎么也忍受不了有个红圈圈在那。开个玩笑，虽然有些习惯看起来可有可无，无关紧要，但这确实映射了一种态度和思维习惯。</p>
<p><strong>完美有多远？我不知道，但我愿意多往前走一步。</strong></p>
<h4>二、拾起初衷</h4>
<p>我们的生活，每天很忙碌。有时候忙得自己都忘记了为什么在此处，有时候忙得只能不断地用直觉、用以往的经验去设计一个解决方案，而没有时间去思考需求是不是合理，方案是不是最佳，我们以为自己设计的是最佳实践，谁知道呢？</p>
<p>这个社会，这个世界，处在一个以不可思议的速度向前直奔的时间线上，我们处在这个时代的浪潮之上，每个人都感到了那种令人窒息的紧迫感。</p>
<p>父母都是不希望孩子太累的，我们见过很多这样的话：</p>
<p style="padding-left: 30px;"><strong>差不多就行了。</strong></p>
<p style="padding-left: 30px;"><strong>糊弄糊弄就完事了。</strong></p>
<p style="padding-left: 30px;"><strong>不要与众不同。</strong></p>
<p style="padding-left: 30px;"><strong>顺其自然。</strong></p>
<p>但是你应该问问自己，是不是真的要 <a href="http://blog.hesey.net/2010/05/is-let-it-be-consolation-or-excuse.html" target="_blank">顺其自然</a> ？</p>
<p>我记得在上大二的时候，听一个叫端木恒的人说过一句话，大意是，<strong>这个世界上，政治可以改变很多事情，而科技，可以通过促进信息的流通，最终去推动政治的变革，去改变整个世界。</strong></p>
<p>当时觉得这事儿太酷了，是的，所以我当时的想法是，要去一个技术足够强大，并且对人们的生活有实质影响的公司。希望用技术的力量去让更多人生活地更好。</p>
<p>这当然是一种不自量力，但又如何呢？只是一个普通人小小的想法，不断追求卓越，愿意比别人多往前走一步而已。</p>
<p>就像冯大辉说的：</p>
<p style="padding-left: 30px;"><strong>所有人都说你做不成，都告诉你不要去做，不靠谱，嘲讽你，而你最后真的把事情做起来了，这就是牛逼。</strong></p>
<p>做成了，其实牛不牛逼对你自己而言已经不重要了。</p>
<p>没做成，所有人都笑你是傻逼，但起码也对得起自己的内心。</p>
<p>再说，如果 <a href="http://blog.hesey.net/2010/05/strength-of-the-young.html" target="_blank">青年人</a> 想的都是养老和退休，那做事的人在哪？</p>
<h4>三、发现更好的自己</h4>
<p>老罗最后的一个问题是：</p>
<p style="padding-left: 30px;"><strong>在一个完美主义者的眼里，这是一个怎样的世界？</strong></p>
<p>这个社会上很多人在生活上追求更高的品质，但愿意对自己手头所做的事情坚持高标准坚持卓越理念的人已经不多见了，以至于我们发现<strong>花再多的钱也买不到安全的食品了，花了一辈子的积蓄买的房子却有各种质量问题。</strong>扪心自问自己在工作中是否能坚持某些东西，大部分人的态度都差不多，只是你糊弄一下不会怎样，而他马虎一点就会死人，区别仅仅在于这里。</p>
<p>M·斯科特·派克说过一句话：</p>
<p style="padding-left: 30px;"><strong>规避问题和逃避问题的趋向，是人类心理疾病的根源。</strong></p>
<p>很多人把随大流把妥协作为一种「成熟」的标志，小时候敢想敢说可能也敢做，长大以后懂得了人情世故，懂得向现实妥协，45度角仰望天空说自己终于长大了。再看身边那些「冥顽不灵」、「认死理」的所谓完美主义者，认为这些人才是不正常的群体，把这些人要么当做傻逼要么当做装逼。</p>
<p>天哪，我都想问，「这是一个怎样的世界？」</p>
<p>肯定有人会说，站着说话不腰疼。诚然，在生活中，有的人是为了活下去，有的人是为了活得更好，有的人是为了帮助别人活得更好。这是不同的人生阶段，每个人的情况不一样，但这并不影响每个人内心的精神寄托和对信念的追求。</p>
<p>我从不指望去改变别人，但我相信我可以改变自己，虽然也很难。</p>
<p>学生都喜欢问，如何最快地告诉自己的能力。说实话，我真的不知道什么是捷径，我的经验就是和比你优秀的人一起工作，经常请教比你资深的人，不断挑战过去的自己（每天审视自己太紧张了，只要比前段时间的自己更好就可以了）。</p>
<h4>四、细节是魔鬼</h4>
<p>Devils are in the details，细节是魔鬼，这句话很多人都听过，但要在工作中时时刻刻注意？难。</p>
<p>前几天给同事做Code Review，就几行代码，发现了一个问题。</p>
<p style="padding-left: 30px;">场景是我们发现某个系统中存在占用内存超大的HTML字符串，需要统计HTML字符串的长度，于是为了获得准确的字节长度，这段代码调用的是String.getBytes().length，一眼看起来并没有什么大问题。</p>
<p style="padding-left: 30px;">但是考虑到本身这个字符串就比较大，联想到Java内部是用UTF-16存储字符串的，而getBytes()会转换为系统默认编码（GBK或是UTF-8等等），这里必然存在底层字符数组的拷贝（可以去参考String.getBytes()的源代码证实），一个本身就很大的字符串，经过拷贝，将会占用更多的内存，加剧这个问题，而在HTML中，中文其实只占了非常小的一部分，所以直接用String.length()，虽然会少数几个字符，但对统计结果影响其实并不大，并且这里不存在任何数组分配的开销。</p>
<p style="padding-left: 30px;">另外建议所有调用String.getBytes()的地方通通显式传入编码，这是个大坑。（<em>陈皓注：用String.length代替getBytes().length，也是在给未来挖坑——如果未来有人要用len来干别的事，那么这个不精确的len可能就是一个大坑</em>）</p>
<p>另外一个案例，也是在Code Review的时候发现的。</p>
<p style="padding-left: 30px;">某个调用场景下，每次都会新建一个解析器对象去解析结果，尽管解析器没有任何实例变量不会产生线程安全问题，创建的开销也并不大，但我还是坚持要改成单例，使用同一个实例去处理，这也符合面向GC编程的思想。</p>
<p style="padding-left: 30px;">这些场景，每天我们都在遇到，<strong>也许我们会说这些都是很小的问题，无伤大雅，差不多就行了。</strong>但就像前面说的，这是一种态度，一种思维习惯，当你坚持用最高的标准去要求自己，去要求自己的工作时，你才有可能渐渐接近卓越。细节是魔鬼，它会在完全察觉不到的时刻，把人拉回平庸。</p>
<p>「我不是为了输赢，我就是认真。」这不代表我们不在乎输赢，从头至尾我都坚信，只有坚持完美，坚持品质，坚持那些我们曾经了解现在可能已经放弃了的美好的东西，像一个老工匠，把一种专注、追求极致的情怀融入我们的作品里，也许有一天，就有人，追寻着 <a href="http://blog.hesey.net/2010/04/a-time-without-dreams.html" target="_blank">梦想</a> ，发现了 <a href="http://blog.hesey.net/2012/02/posibilities-of-life.html" target="_blank">生活更多的可能性</a> ，像乔布斯、像贝索斯，改变整个行业，改变全世界。</p>
<p>我们是被这个时代推上浪潮之巅的人，是去做一个见证者，或是一个冲在最前面也不怕被拍死的傻瓜，是我们每个人选择的权利。</p>
<p>只是不要忘记，那些傻瓜，不是真的不怕死，<strong>他们只是认真</strong>。</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" id="wp_rp_first"><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/10/communication-150x150.png" alt="聊聊团队协同和协同工具" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_title">聊聊团队协同和协同工具</a></li><li ><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/http_method-150x150.png" alt="“一把梭：REST API 全用 POST”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_title">“一把梭：REST API 全用 POST”</a></li><li ><a href="https://coolshell.cn/articles/22157.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/monitoring-150x150.jpeg" alt="谈谈公司对员工的监控" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22157.html" class="wp_rp_title">谈谈公司对员工的监控</a></li><li ><a href="https://coolshell.cn/articles/21589.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2021/07/knowledge_sharing-300x169-1-150x150.jpeg" alt="如何做一个有质量的技术分享" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21589.html" class="wp_rp_title">如何做一个有质量的技术分享</a></li><li ><a href="https://coolshell.cn/articles/20977.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/08/programmer.01-e1596792460687-150x150.png" alt="程序员如何把控自己的职业" width="150" height="150" /></a><a href="https://coolshell.cn/articles/20977.html" class="wp_rp_title">程序员如何把控自己的职业</a></li><li ><a href="https://coolshell.cn/articles/20765.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/01/remote-150x150.jpg" alt="MegaEase的远程工作文化" width="150" height="150" /></a><a href="https://coolshell.cn/articles/20765.html" class="wp_rp_title">MegaEase的远程工作文化</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/11629.html">「我只是认真」聊聊工匠情怀</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/11629.html/feed</wfw:commentRss>
			<slash:comments>78</slash:comments>
		
		
			</item>
		<item>
		<title>面向GC的Java编程</title>
		<link>https://coolshell.cn/articles/11541.html</link>
					<comments>https://coolshell.cn/articles/11541.html#comments</comments>
		
		<dc:creator><![CDATA[王 晨纯]]></dc:creator>
		<pubDate>Wed, 07 May 2014 03:24:38 +0000</pubDate>
				<category><![CDATA[Java语言]]></category>
		<category><![CDATA[GC]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JVM]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=11541</guid>

					<description><![CDATA[<p>（感谢网友 @Hesey小纯纯 投稿  博客 &#124;　原文链接） Java程序员在编码过程中通常不需要考虑内存问题，JVM经过高度优化的GC机制大部分情况下都能够很...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/11541.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/11541.html">面向GC的Java编程</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><strong>（感谢网友 <a href="http://weibo.com/tbmujian" target="_blank">@Hesey小纯纯</a> 投稿  <a href="http://blog.hesey.net/" target="_blank">博客</a> |　<a href="http://blog.hesey.net/2014/05/gc-oriented-java-programming.html" target="_blank">原文链接</a>）</strong></p>
<p>Java程序员在编码过程中通常不需要考虑内存问题，JVM经过高度优化的GC机制大部分情况下都能够很好地处理堆(Heap)的清理问题。以至于许多Java程序员认为，我只需要关心何时创建对象，而回收对象，就交给GC来做吧！甚至有人说，如果在编程过程中频繁考虑内存问题，是一种退化，这些事情应该交给编译器，交给虚拟机来解决。</p>
<p>这话其实也没有太大问题，的确，大部分场景下关心内存、GC的问题，显得有点“杞人忧天”了，高老爷说过：</p>
<p style="padding-left: 30px;">过早优化是万恶之源。</p>
<p>但另一方面，<strong>什么才是“过早优化”？</strong></p>
<p style="padding-left: 30px;">If we could do things right for the first time, why not?</p>
<p>事实上<strong>JVM的内存模型</strong>( <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/" target="_blank">JMM</a> )理应是Java程序员的基础知识，处理过几次JVM线上内存问题之后就会很明显感受到，很多系统问题，都是内存问题。</p>
<p>对JVM内存结构感兴趣的同学可以看下 <a href="http://blog.hesey.net/2011/04/introduction-to-java-virtual-machine.html" target="_blank">浅析Java虚拟机结构与机制</a> 这篇文章，本文就不再赘述了，本文也并不关注具体的GC算法，相关的文章汗牛充栋，随时可查。</p>
<p>另外，不要指望GC优化的这些技巧，可以对应用性能有成倍的提高，特别是对I/O密集型的应用，或是实际落在YoungGC上的优化，可能效果只是帮你减少那么一点YoungGC的频率。</p>
<p>但我认为，<strong>优秀程序员的价值，不在于其所掌握的几招屠龙之术，而是在细节中见真著</strong>，就像前面说的，<strong>如果我们可以一次把事情做对，并且做好，在允许的范围内尽可能追求卓越，为什么不去做呢？</strong><span id="more-11541"></span></p>
<h4>一、GC分代的基本假设</h4>
<p>大部分GC算法，都将堆内存做分代(Generation)处理，但是为什么要分代呢，又为什么不叫内存分区、分段，而要用面向时间、年龄的“代”来表示不同的内存区域？</p>
<p>GC分代的<strong>基本假设</strong>是：</p>
<p style="padding-left: 30px;"><strong>绝大部分对象的生命周期都非常短暂，存活时间短。</strong></p>
<p>而这些短命的对象，恰恰是GC算法需要首先关注的。所以在大部分的GC中，YoungGC（也称作MinorGC）占了绝大部分，对于负载不高的应用，可能跑了数个月都不会发生FullGC。</p>
<p>基于这个前提，在编码过程中，我们应该<strong>尽可能地缩短对象的生命周期</strong>。在过去，分配对象是一个比较重的操作，所以有些程序员会尽可能地减少new对象的次数，尝试减小堆的分配开销，减少内存碎片。</p>
<p>但是，短命对象的创建在JVM中比我们想象的性能更好，所以，不要吝啬new关键字，大胆地去new吧。</p>
<p>当然前提是不做无谓的创建，对象创建的速率越高，那么GC也会越快被触发。</p>
<p>结论：</p>
<ul>
<li>分配小对象的开销分享小，不要吝啬去创建。</li>
<li>GC最喜欢这种小而短命的对象。</li>
<li>让对象的生命周期尽可能短，例如在方法体内创建，使其能尽快地在YoungGC中被回收，不会晋升(romote)到年老代(Old Generation)。</li>
</ul>
<h4>二、对象分配的优化</h4>
<p>基于大部分对象都是小而短命，并且不存在多线程的数据竞争。这些小对象的分配，会优先在线程私有的<strong> TLAB</strong> 中分配，TLAB中创建的对象，不存在锁甚至是CAS的开销。</p>
<p>TLAB占用的空间在Eden Generation。</p>
<p>当对象比较大，TLAB的空间不足以放下，而JVM又认为当前线程占用的TLAB剩余空间还足够时，就会直接在Eden Generation上分配，此时是存在并发竞争的，所以会有CAS的开销，但也还好。</p>
<p>当对象大到Eden Generation放不下时，JVM只能尝试去Old Generation分配，这种情况需要尽可能避免，因为一旦在Old Generation分配，这个对象就只能被Old Generation的GC或是FullGC回收了。</p>
<h4>三、不可变对象的好处</h4>
<p>GC算法在扫描存活对象时通常需要从ROOT节点开始，扫描所有存活对象的引用，构建出对象图。</p>
<p>不可变对象对GC的优化，主要体现在Old Generation中。</p>
<p>可以想象一下，如果存在Old Generation的对象引用了Young Generation的对象，那么在每次YoungGC的过程中，就必须考虑到这种情况。</p>
<p>Hotspot JVM为了提高YoungGC的性能，避免每次YoungGC都扫描Old Generation中的对象引用，采用了 <strong>卡表(Card Table) </strong>的方式。</p>
<p>简单来说，当Old Generation中的对象发生对Young Generation中的对象产生新的引用关系或释放引用时，都会在卡表中响应的标记上标记为脏(dirty)，而YoungGC时，只需要扫描这些dirty的项就可以了。</p>
<p>可变对象对其它对象的引用关系可能会频繁变化，并且有可能在运行过程中持有越来越多的引用，特别是容器。这些都会导致对应的卡表项被频繁标记为dirty。</p>
<p>而不可变对象的引用关系非常稳定，在扫描卡表时就不会扫到它们对应的项了。</p>
<p>注意，这里的不可变对象，不是指仅仅自身引用不可变的final对象，而是真正的<strong><span style="color: #ff0000;">Immutable Objects</span></strong>。</p>
<h4>四、引用置为null的传说</h4>
<p>早期的很多Java资料中都会提到在方法体中将一个变量置为null能够优化GC的性能，类似下面的代码：</p>
<pre data-enlighter-language="java" class="EnlighterJSRAW">List&lt;String&gt; list = new ArrayList&lt;String&gt;();
// some code
list = null; // help GC
</pre>
<p>事实上这种做法对GC的帮助微乎其微，有时候反而会导致代码混乱。</p>
<p>我记得几年前 @rednaxelafx 在HLL VM小组中详细论述过这个问题，原帖我没找到，结论基本就是：</p>
<ul>
<li>在一个非常大的方法体内，对一个较大的对象，将其引用置为null，某种程度上可以帮助GC。</li>
<li>大部分情况下，这种行为都没有任何好处。</li>
</ul>
<p>所以，还是早点放弃这种“优化”方式吧。</p>
<p>GC比我们想象的更聪明。</p>
<h4>五、手动档的GC</h4>
<p>在很多Java资料上都有下面两个奇技淫巧：</p>
<ul>
<li>通过<strong>Thread.yield()</strong>让出CPU资源给其它线程。</li>
<li>通过<strong>System.gc()</strong>触发GC。</li>
</ul>
<p>事实上JVM从不保证这两件事，而System.gc()在JVM启动参数中如果允许显式GC，则会<strong>触发FullGC</strong>，对于响应敏感的应用来说，几乎等同于自杀。</p>
<p>So，让我们牢记两点：</p>
<ul>
<li>Never use Thread.yield()。</li>
<li>Never use System.gc()。除非你真的需要回收Native Memory。</li>
</ul>
<p>第二点有个Native Memory的例外，如果你在以下场景：</p>
<ul>
<li>使用了NIO或者NIO框架（Mina/Netty）</li>
<li>使用了DirectByteBuffer分配字节缓冲区</li>
<li>使用了MappedByteBuffer做内存映射</li>
</ul>
<p>由于<strong>Native Memory只能通过FullGC（或是CMS GC）回收</strong>，所以除非你非常清楚这时真的有必要，否则不要轻易调用System.gc()，且行且珍惜。</p>
<p>另外为了防止某些框架中的System.gc调用（例如NIO框架、Java RMI），建议在启动参数中加上-XX:+DisableExplicitGC来禁用显式GC。</p>
<p>这个参数有个巨大的坑，如果你禁用了System.gc()，那么上面的3种场景下的内存就无法回收，可能造成OOM，如果你使用了CMS GC，那么可以用这个参数替代：-XX:+ExplicitGCInvokesConcurrent。</p>
<p>关于System.gc()，可以参考 @bluedavy 的几篇文章：</p>
<ul>
<li><a href="http://hellojava.info/?p=56" target="_blank">CMS GC会不会回收Direct ByteBuffer的内存</a></li>
<li><a href="http://hellojava.info/?p=323" target="_blank">说说在Java启动参数上我犯的错</a></li>
<li><a href="http://hellojava.info/?p=319" target="_blank">java.lang.OutOfMemoryError:Map failed</a></li>
</ul>
<p>&nbsp;</p>
<h4>六、指定容器初始化大小</h4>
<p>Java容器的一个特点就是可以动态扩展，所以通常我们都不会去考虑初始大小的设置，不够了反正会自动扩容呗。</p>
<p>但是扩容不意味着没有代价，甚至是很高的代价。</p>
<p>例如一些基于数组的数据结构，例如StringBuilder、StringBuffer、ArrayList、HashMap等等，在扩容的时候都需要做ArrayCopy，对于不断增长的结构来说，经过若干次扩容，会存在大量无用的老数组，而回收这些数组的压力，全都会加在GC身上。</p>
<p>这些容器的构造函数中通常都有一个可以指定大小的参数，如果对于某些大小可以预估的容器，建议加上这个参数。</p>
<p>可是因为容器的扩容并不是等到容器满了才扩容，而是有一定的比例，例如HashMap的扩容阈值和负载因子(loadFactor)相关。</p>
<p>Google Guava框架对于容器的初始容量提供了非常便捷的工具方法，例如：</p>
<p>[code lang=&#8221;java&#8221;]Lists.newArrayListWithCapacity(initialArraySize);</p>
<p>Lists.newArrayListWithExpectedSize(estimatedSize);</p>
<p>Sets.newHashSetWithExpectedSize(expectedSize);</p>
<p>Maps.newHashMapWithExpectedSize(expectedSize);<br />
[/code]</p>
<p>这样我们只要传入预估的大小即可，容量的计算就交给Guava来做吧。</p>
<p><strong>反例</strong>：如果采用默认无参构造函数，创建一个ArrayList，不断增加元素直到OOM，那么在此过程中会导致：</p>
<ul>
<li>多次数组扩容，重新分配更大空间的数组</li>
<li>多次数组拷贝</li>
<li>内存碎片</li>
</ul>
<h4>七、对象池</h4>
<p>为了减少对象分配开销，提高性能，可能有人会采取对象池的方式来缓存对象集合，作为复用的手段。</p>
<p>但是对象池中的对象由于在运行期长期存活，大部分会晋升到Old Generation，因此无法通过YoungGC回收。</p>
<p>并且通常……没有什么效果。</p>
<p>对于对象本身：</p>
<ul>
<li>如果对象很小，那么分配的开销本来就小，对象池只会增加代码复杂度。</li>
<li>如果对象比较大，那么晋升到Old Generation后，对GC的压力就更大了。</li>
</ul>
<p>从线程安全的角度考虑，通常池都是会被并发访问的，那么你就需要处理好同步的问题，这又是一个大坑，并且<strong>同步带来的开销，未必比你重新创建一个对象小</strong>。</p>
<p>对于对象池，唯一合适的场景就是<strong>当池中的每个对象的创建开销很大</strong>时，缓存复用才有意义，例如每次new都会创建一个连接，或是依赖一次RPC。</p>
<p>比如说：</p>
<ul>
<li>线程池</li>
<li>数据库连接池</li>
<li>TCP连接池</li>
</ul>
<p>即使你真的需要实现一个对象池，也请使用成熟的开源框架，例如Apache Commons Pool。</p>
<p>另外，使用JDK的ThreadPoolExecutor作为线程池，不要重复造轮子，除非当你看过AQS的源码后认为你可以写得比Doug Lea更好。</p>
<h4>八、对象作用域</h4>
<p>尽可能缩小对象的作用域，即生命周期。</p>
<ul>
<li>如果可以在方法内声明的局部变量，就不要声明为实例变量。</li>
<li>除非你的对象是单例的或不变的，否则尽可能少地声明static变量。</li>
</ul>
<h4>九、各类引用</h4>
<p>java.lang.ref.Reference有几个子类，用于处理和GC相关的引用。JVM的引用类型简单来说有几种：</p>
<ul>
<li>Strong Reference，最常见的引用</li>
<li>Weak Reference，当没有指向它的强引用时会被GC回收</li>
<li>Soft Reference，只当临近OOM时才会被GC回收</li>
<li>Phantom Reference，主要用于识别对象被GC的时机，通常用于做一些清理工作</li>
</ul>
<p>当你需要实现一个缓存时，可以考虑优先使用WeakHashMap，而不是HashMap，当然，更好的选择是使用框架，例如Guava Cache。</p>
<p>最后，再次提醒，以上的这些未必可以对代码有多少性能上的提升，但是熟悉这些方法，是为了帮助我们写出更卓越的代码，和GC更好地合作。</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/2631.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/8.jpg" alt="五大基于JVM的脚本语言" width="150" height="150" /></a><a href="https://coolshell.cn/articles/2631.html" class="wp_rp_title">五大基于JVM的脚本语言</a></li><li ><a href="https://coolshell.cn/articles/1252.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/5.jpg" alt="G1新型垃圾回收器一瞥" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1252.html" class="wp_rp_title">G1新型垃圾回收器一瞥</a></li><li ><a href="https://coolshell.cn/articles/20845.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/03/rust-social-wide-150x150.jpg" alt="Rust语言的编程范式" width="150" height="150" /></a><a href="https://coolshell.cn/articles/20845.html" class="wp_rp_title">Rust语言的编程范式</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/11454.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="从LongAdder看更高效的无锁实现" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11454.html" class="wp_rp_title">从LongAdder看更高效的无锁实现</a></li><li ><a href="https://coolshell.cn/articles/11175.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/03/cow-copy-150x150.jpg" alt="Java中的CopyOnWrite容器" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11175.html" class="wp_rp_title">Java中的CopyOnWrite容器</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/11541.html">面向GC的Java编程</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/11541.html/feed</wfw:commentRss>
			<slash:comments>46</slash:comments>
		
		
			</item>
	</channel>
</rss>
