YGC問(wèn)題排查仅叫,又讓我漲姿勢(shì)了!

在高并發(fā)下糙捺,Java程序的GC問(wèn)題屬于很典型的一類(lèi)問(wèn)題诫咱,帶來(lái)的影響往往會(huì)被進(jìn)一步放大。不管是「GC頻率過(guò)快」還是「GC耗時(shí)太長(zhǎng)」洪灯,由于GC期間都存在Stop The World問(wèn)題坎缭,因此很容易導(dǎo)致服務(wù)超時(shí),引發(fā)性能問(wèn)題签钩。

我們團(tuán)隊(duì)負(fù)責(zé)的廣告系統(tǒng)承接了比較大的C端流量掏呼,平峰期間的請(qǐng)求量基本達(dá)到了上千QPS,過(guò)去也遇到了很多次GC相關(guān)的線(xiàn)上問(wèn)題边臼。

這篇文章哄尔,我再分享一個(gè)更棘手的Young GC耗時(shí)過(guò)長(zhǎng)的線(xiàn)上案例,同時(shí)會(huì)整理下YGC相關(guān)的知識(shí)點(diǎn)柠并,希望讓你有所收獲岭接。內(nèi)容分成以下2個(gè)部分:

  • 從一次YGC耗時(shí)過(guò)長(zhǎng)的案例說(shuō)起
  • YGC的相關(guān)知識(shí)點(diǎn)總結(jié)

從一次YGC耗時(shí)過(guò)長(zhǎng)的案例說(shuō)起

今年4月份,我們的廣告服務(wù)在新版本上線(xiàn)后臼予,收到了大量的服務(wù)超時(shí)告警鸣戴,通過(guò)下面的監(jiān)控圖可以看到:超時(shí)量突然大面積增加,1分鐘內(nèi)甚至達(dá)到了上千次接口超時(shí)粘拾。下面詳細(xì)介紹下該問(wèn)題的排查過(guò)程窄锅。

檢查監(jiān)控

收到告警后,我們第一時(shí)間查看了監(jiān)控系統(tǒng)缰雇,立馬發(fā)現(xiàn)了YoungGC耗時(shí)過(guò)長(zhǎng)的異常入偷。我們的程序大概在21點(diǎn)50左右上線(xiàn)追驴,通過(guò)下圖可以看出:在上線(xiàn)之前,YGC基本幾十毫秒內(nèi)完成疏之,而上線(xiàn)后YGC耗時(shí)明顯變長(zhǎng)殿雪,最長(zhǎng)甚至達(dá)到了3秒多。

由于YGC期間程序會(huì)Stop The World锋爪,而我們上游系統(tǒng)設(shè)置的服務(wù)超時(shí)時(shí)間都在幾百毫秒丙曙,因此推斷:是因?yàn)閅GC耗時(shí)過(guò)長(zhǎng)引發(fā)了服務(wù)大面積超時(shí)。
按照GC問(wèn)題的常規(guī)排查流程其骄,我們立刻摘掉了一個(gè)節(jié)點(diǎn)亏镰,然后通過(guò)以下命令dump了堆內(nèi)存文件用來(lái)保留現(xiàn)場(chǎng)。
jmap -dump:format=b,file=heap pid
最后對(duì)線(xiàn)上服務(wù)做了回滾處理拯爽,回滾后服務(wù)立馬恢復(fù)了正常索抓,接下來(lái)就是長(zhǎng)達(dá)1天的問(wèn)題排查和修復(fù)過(guò)程。

確認(rèn)JVM配置

用下面的命令某抓,我們?cè)俅螜z查了JVM的參數(shù)

ps aux | grep "applicationName=adsearch"
-Xms4g -Xmx4g -Xmn2g -Xss1024K 
-XX:ParallelGCThreads=5 
-XX:+UseConcMarkSweepGC 
-XX:+UseParNewGC 
-XX:+UseCMSCompactAtFullCollection 
-XX:CMSInitiatingOccupancyFraction=80

可以看到堆內(nèi)存為4G纸兔,新生代和老年代均為2G,新生代采用ParNew收集器否副。
再通過(guò)命令 jmap -heap pid 查到:新生代的Eden區(qū)為1.6G汉矿,S0和S1區(qū)均為0.2G。
本次上線(xiàn)并未修改JVM相關(guān)的任何參數(shù)备禀,同時(shí)我們服務(wù)的請(qǐng)求量基本和往常持平洲拇。因此猜測(cè):此問(wèn)題大概率和上線(xiàn)的代碼相關(guān)。

檢查代碼

再回到Y(jié)GC的原理來(lái)思考這個(gè)問(wèn)題曲尸,一次YGC的過(guò)程主要包括以下兩個(gè)步驟:

1赋续、從GC Root掃描對(duì)象,對(duì)存活對(duì)象進(jìn)行標(biāo)注
2另患、將存活對(duì)象復(fù)制到S1區(qū)或者晉升到Old區(qū)

根據(jù)下面的監(jiān)控圖可以看出:正常情況下纽乱,Survivor區(qū)的使用率一直維持在很低的水平(大概30M左右),但是上線(xiàn)后昆箕,Survivor區(qū)的使用率開(kāi)始波動(dòng)鸦列,最多的時(shí)候快占滿(mǎn)0.2G了。而且鹏倘,YGC耗時(shí)和Survivor區(qū)的使用率基本成正相關(guān)薯嗤。因此,我們推測(cè):應(yīng)該是長(zhǎng)生命周期的對(duì)象越來(lái)越多纤泵,導(dǎo)致標(biāo)注和復(fù)制過(guò)程的耗時(shí)增加骆姐。

再回到服務(wù)的整體表現(xiàn):上游流量并沒(méi)有出現(xiàn)明顯變化,正常情況下,核心接口的響應(yīng)時(shí)間也基本在200ms以?xún)?nèi)玻褪,YGC的頻率大概每8秒進(jìn)行1次肉渴。

很顯然,對(duì)于局部變量來(lái)說(shuō)归园,在每次YGC后就能夠馬上被回收了黄虱。那為什么還會(huì)有如此多的對(duì)象在YGC后存活下來(lái)呢?

我們進(jìn)一步將懷疑對(duì)象鎖定在:程序的全局變量或者類(lèi)靜態(tài)變量上庸诱。但是diff了本次上線(xiàn)的代碼,我們并未發(fā)現(xiàn)代碼中有引入此類(lèi)變量晤揣。

對(duì)dump的堆內(nèi)存文件進(jìn)行分析

代碼排查沒(méi)有進(jìn)展后桥爽,我們開(kāi)始從堆內(nèi)存文件中尋找線(xiàn)索,使用MAT工具導(dǎo)入了第1步dump出來(lái)的堆文件后昧识,然后通過(guò)Dominator Tree視圖查看到了當(dāng)前堆中的所有大對(duì)象钠四。

立馬發(fā)現(xiàn)NewOldMappingService這個(gè)類(lèi)所占的空間很大,通過(guò)代碼定位到:這個(gè)類(lèi)位于第三方的client包中跪楞,由我們公司的商品團(tuán)隊(duì)提供缀去,用于實(shí)現(xiàn)新舊類(lèi)目轉(zhuǎn)換(最近商品團(tuán)隊(duì)在對(duì)類(lèi)目體系進(jìn)行改造,為了兼容舊業(yè)務(wù)甸祭,需要進(jìn)行新舊類(lèi)目映射)缕碎。

進(jìn)一步查看代碼,發(fā)現(xiàn)這個(gè)類(lèi)中存在大量的靜態(tài)HashMap池户,用于緩存新舊類(lèi)目轉(zhuǎn)換時(shí)需要用到的各種數(shù)據(jù)咏雌,以減少RPC調(diào)用,提高轉(zhuǎn)換性能校焦。

原本以為赊抖,非常接近問(wèn)題的真相了,但是深入排查發(fā)現(xiàn):這個(gè)類(lèi)的所有靜態(tài)變量全部在類(lèi)加載時(shí)就初始化完數(shù)據(jù)了寨典,雖然會(huì)占到100多M的內(nèi)存氛雪,但是之后基本不會(huì)再新增數(shù)據(jù)。并且耸成,這個(gè)類(lèi)早在3月份就上線(xiàn)使用了报亩,client包的版本也一直沒(méi)變過(guò)。

經(jīng)過(guò)上面種種分析墓猎,這個(gè)類(lèi)的靜態(tài)HashMap會(huì)一直存活捆昏,經(jīng)過(guò)多輪YGC后,最終晉升到老年代中毙沾,它不應(yīng)該是YGC持續(xù)耗時(shí)過(guò)長(zhǎng)的原因骗卜。因此,我們暫時(shí)排除了這個(gè)可疑點(diǎn)。

分析YGC處理Reference的耗時(shí)

團(tuán)隊(duì)對(duì)于YGC問(wèn)題的排查經(jīng)驗(yàn)很少寇仓,不知道再往下該如何分析了举户。基本掃光了網(wǎng)上可查到的所有案例遍烦,發(fā)現(xiàn)原因集中在這兩類(lèi)上:

1俭嘁、對(duì)存活對(duì)象標(biāo)注時(shí)間過(guò)長(zhǎng):比如重載了Object類(lèi)的Finalize方法,導(dǎo)致標(biāo)注Final Reference耗時(shí)過(guò)長(zhǎng)服猪;或者String.intern方法使用不當(dāng)供填,導(dǎo)致YGC掃描StringTable時(shí)間過(guò)長(zhǎng)。
2罢猪、長(zhǎng)周期對(duì)象積累過(guò)多:比如本地緩存使用不當(dāng)近她,積累了太多存活對(duì)象;或者鎖競(jìng)爭(zhēng)嚴(yán)重導(dǎo)致線(xiàn)程阻塞膳帕,局部變量的生命周期變長(zhǎng)粘捎。

針對(duì)第1類(lèi)問(wèn)題,可以通過(guò)以下參數(shù)顯示GC處理Reference的耗時(shí)-XX:+PrintReferenceGC危彩。添加此參數(shù)后攒磨,可以看到不同類(lèi)型的 reference 處理耗時(shí)都很短,因此又排除了此項(xiàng)因素汤徽。

再回到長(zhǎng)周期對(duì)象進(jìn)行分析

再往后娩缰,我們添加了各種GC參數(shù)試圖尋找線(xiàn)索都沒(méi)有結(jié)果,似乎要黔驢技窮泻骤,沒(méi)有思路了漆羔。綜合監(jiān)控和種種分析來(lái)看:應(yīng)該只有長(zhǎng)周期對(duì)象才會(huì)引發(fā)我們這個(gè)問(wèn)題。
折騰了好幾個(gè)小時(shí)狱掂,最終峰回路轉(zhuǎn)演痒,一個(gè)小伙伴重新從MAT堆內(nèi)存中找到了第二個(gè)懷疑點(diǎn)。

從上面的截圖可以看到:大對(duì)象中排在第3位的ConfigService類(lèi)進(jìn)入了我們的視野趋惨,該類(lèi)的一個(gè)ArrayList變量中竟然包含了270W個(gè)對(duì)象鸟顺,而且大部分都是相同的元素。
ConfigService這個(gè)類(lèi)在第三方Apollo的包中器虾,不過(guò)源代碼被公司架構(gòu)部進(jìn)行了二次改造讯嫂,通過(guò)代碼可以看出:問(wèn)題出在了第11行,每次調(diào)用getConfig方法時(shí)都會(huì)往List中添加元素兆沙,并且未做去重處理欧芽。

我們的廣告服務(wù)在apollo中存儲(chǔ)了大量的廣告策略配置,而且大部分請(qǐng)求都會(huì)調(diào)用ConfigService的getConfig方法來(lái)獲取配置葛圃,因此會(huì)不斷地往靜態(tài)變量namespaces中添加新對(duì)象千扔,從而引發(fā)此問(wèn)題憎妙。

至此,整個(gè)問(wèn)題終于水落石出了曲楚。這個(gè)BUG是因?yàn)榧軜?gòu)部在對(duì)apollo client包進(jìn)行定制化開(kāi)發(fā)時(shí)不小心引入的厘唾,很顯然沒(méi)有經(jīng)過(guò)仔細(xì)測(cè)試,并且剛好在我們上線(xiàn)前一天發(fā)布到了中央倉(cāng)庫(kù)中龙誊,而公司基礎(chǔ)組件庫(kù)的版本是通過(guò)super-pom方式統(tǒng)一維護(hù)的抚垃,業(yè)務(wù)無(wú)感知。

解決方案

為了快速驗(yàn)證YGC耗時(shí)過(guò)長(zhǎng)是因?yàn)榇藛?wèn)題導(dǎo)致的趟大,我們?cè)谝慌_(tái)服務(wù)器上直接用舊版本的apollo client 包進(jìn)行了替換鹤树,然后重啟了服務(wù),觀察了將近20分鐘逊朽,YGC恢復(fù)正常魂迄。
最后,我們通知架構(gòu)部修復(fù)BUG惋耙,重新發(fā)布了super-pom,徹底解決了這個(gè)問(wèn)題熊昌。
02 YGC的相關(guān)知識(shí)點(diǎn)總結(jié)
通過(guò)上面這個(gè)案例绽榛,可以看到Y(jié)GC問(wèn)題其實(shí)比較難排查。相比FGC或者OOM婿屹,YGC的日志很簡(jiǎn)單灭美,只知道新生代內(nèi)存的變化和耗時(shí),同時(shí)dump出來(lái)的堆內(nèi)存必須要仔細(xì)排查才行昂利。

另外届腐,如果不清楚YGC的流程,排查起來(lái)會(huì)更加困難蜂奸。這里犁苏,我對(duì)YGC相關(guān)的知識(shí)點(diǎn)再做下梳理,方便大家更全面的理解YGC扩所。

YGC的相關(guān)知識(shí)點(diǎn)總結(jié)

5個(gè)問(wèn)題重新認(rèn)識(shí)新生代

YGC 在新生代中進(jìn)行围详,首先要清楚新生代的堆結(jié)構(gòu)劃分。新生代分為Eden區(qū)和兩個(gè)Survivor區(qū)祖屏,其中Eden:from:to = 8:1:1 (比例可以通過(guò)參數(shù) –XX:SurvivorRatio 來(lái)設(shè)定 )助赞,這是最基本的認(rèn)識(shí)。

為什么會(huì)有新生代袁勺?

如果不分代雹食,所有對(duì)象全部在一個(gè)區(qū)域,每次GC都需要對(duì)全堆進(jìn)行掃描期丰,存在效率問(wèn)題群叶。分代后吃挑,可分別控制回收頻率,并采用不同的回收算法盖呼,確保GC性能全局最優(yōu)儒鹿。

為什么新生代會(huì)采用復(fù)制算法?

新生代的對(duì)象朝生夕死几晤,大約90%的新建對(duì)象可以被很快回收约炎,復(fù)制算法成本低,同時(shí)還能保證空間沒(méi)有碎片蟹瘾。雖然標(biāo)記整理算法也可以保證沒(méi)有碎片圾浅,但是由于新生代要清理的對(duì)象數(shù)量很大,將存活的對(duì)象整理到待清理對(duì)象之前憾朴,需要大量的移動(dòng)操作狸捕,時(shí)間復(fù)雜度比復(fù)制算法高。

為什么新生代需要兩個(gè)Survivor區(qū)众雷?

為了節(jié)省空間考慮灸拍,如果采用傳統(tǒng)的復(fù)制算法,只有一個(gè)Survivor區(qū)砾省,則Survivor區(qū)大小需要等于Eden區(qū)大小鸡岗,此時(shí)空間消耗是8 * 2,而兩塊Survivor可以保持新對(duì)象始終在Eden區(qū)創(chuàng)建编兄,存活對(duì)象在Survivor之間轉(zhuǎn)移即可轩性,空間消耗是8+1+1,明顯后者的空間利用率更高狠鸳。

新生代的實(shí)際可用空間是多少揣苏?

YGC后,總有一塊Survivor區(qū)是空閑的件舵,因此新生代的可用內(nèi)存空間是90%卸察。在YGC的log中或者通過(guò) jmap -heap pid 命令查看新生代的空間時(shí),如果發(fā)現(xiàn)capacity只有90%芦圾,不要覺(jué)得奇怪蛾派。

Eden區(qū)是如何加速內(nèi)存分配的?

HotSpot虛擬機(jī)使用了兩種技術(shù)來(lái)加快內(nèi)存分配个少。分別是bump-the-pointer和TLAB(Thread Local Allocation Buffers)洪乍。

由于Eden區(qū)是連續(xù)的,因此bump-the-pointer在對(duì)象創(chuàng)建時(shí)夜焦,只需要檢查最后一個(gè)對(duì)象后面是否有足夠的內(nèi)存即可壳澳,從而加快內(nèi)存分配速度。

TLAB技術(shù)是對(duì)于多線(xiàn)程而言的茫经,在Eden中為每個(gè)線(xiàn)程分配一塊區(qū)域巷波,減少內(nèi)存分配時(shí)的鎖沖突萎津,加快內(nèi)存分配速度,提升吞吐量抹镊。

新生代的4種回收器

SerialGC(串行回收器)锉屈,最古老的一種,單線(xiàn)程執(zhí)行垮耳,適合單CPU場(chǎng)景颈渊。

ParNew(并行回收器),將串行回收器多線(xiàn)程化终佛,適合多CPU場(chǎng)景俊嗽,需要搭配老年代CMS回收器一起使用。

ParallelGC(并行回收器)铃彰,和ParNew不同點(diǎn)在于它關(guān)注吞吐量绍豁,可設(shè)置期望的停頓時(shí)間,它在工作時(shí)會(huì)自動(dòng)調(diào)整堆大小和其他參數(shù)牙捉。

G1(Garage-First回收器)竹揍,JDK 9及以后版本的默認(rèn)回收器,兼顧新生代和老年代邪铲,將堆拆成一系列Region鬼佣,不要求內(nèi)存塊連續(xù),新生代仍然是并行收集霜浴。

上述回收器均采用復(fù)制算法,都是獨(dú)占式的蓝纲,執(zhí)行期間都會(huì)Stop The World.

YGC的觸發(fā)時(shí)機(jī)

當(dāng)Eden區(qū)空間不足時(shí)阴孟,就會(huì)觸發(fā)YGC。結(jié)合新生代對(duì)象的內(nèi)存分配看下詳細(xì)過(guò)程:

1税迷、新對(duì)象會(huì)先嘗試在棧上分配永丝,如果不行則嘗試在TLAB分配,否則再看是否滿(mǎn)足大對(duì)象條件要在老年代分配箭养,最后才考慮在Eden區(qū)申請(qǐng)空間慕嚷。

2、如果Eden區(qū)沒(méi)有合適的空間毕泌,則觸發(fā)YGC喝检。

3、YGC時(shí)撼泛,對(duì)Eden區(qū)和From Survivor區(qū)的存活對(duì)象進(jìn)行處理挠说,如果滿(mǎn)足動(dòng)態(tài)年齡判斷的條件或者To Survivor區(qū)空間不夠則直接進(jìn)入老年代,如果老年代空間也不夠了愿题,則會(huì)發(fā)生promotion failed损俭,觸發(fā)老年代的回收蛙奖。否則將存活對(duì)象復(fù)制到To Survivor區(qū)。

4杆兵、此時(shí)Eden區(qū)和From Survivor區(qū)的剩余對(duì)象均為垃圾對(duì)象雁仲,可直接抹掉回收。

此外琐脏,老年代如果采用的是CMS回收器攒砖,為了減少CMS Remark階段的耗時(shí),也有可能會(huì)觸發(fā)一次YGC骆膝,這里不作展開(kāi)祭衩。

YGC的執(zhí)行過(guò)程

YGC采用的復(fù)制算法,主要分成以下兩個(gè)步驟:

1阅签、查找GC Roots掐暮,將其引用的對(duì)象拷貝到S1區(qū)
2、遞歸遍歷第1步的對(duì)象政钟,拷貝其引用的對(duì)象到S1區(qū)或者晉升到Old區(qū)

上述整個(gè)過(guò)程都是需要暫停業(yè)務(wù)線(xiàn)程的(STW)路克,不過(guò)ParNew等新生代回收器可以多線(xiàn)程并行執(zhí)行,提高處理效率养交。
YGC通過(guò)可達(dá)性分析算法精算,從GC Root(可達(dá)對(duì)象的起點(diǎn))開(kāi)始向下搜索,標(biāo)記出當(dāng)前存活的對(duì)象碎连,那么剩下未被標(biāo)記的對(duì)象就是需要回收的對(duì)象灰羽。

可作為YGC時(shí)GC Root的對(duì)象包括以下幾種:

1、虛擬機(jī)棧中引用的對(duì)象
2鱼辙、方法區(qū)中靜態(tài)屬性廉嚼、常量引用的對(duì)象
3、本地方法棧中引用的對(duì)象
4倒戏、被Synchronized鎖持有的對(duì)象
5怠噪、記錄當(dāng)前被加載類(lèi)的SystemDictionary
6、記錄字符串常量引用的StringTable
7杜跷、存在跨代引用的對(duì)象
8傍念、和GC Root處于同一CardTable的對(duì)象

其中1-3是大家容易想到的,而4-8很容易被忽視葛闷,卻極有可能是分析YGC問(wèn)題時(shí)的線(xiàn)索入口憋槐。

另外需要注意的是,針對(duì)下圖中跨代引用的情況淑趾,老年代的對(duì)象A也必須作為GC Root的一部分秦陋,但是如果每次YGC時(shí)都去掃描老年代,肯定存在效率問(wèn)題治笨。在HotSpot JVM驳概,引入卡表(Card Table)來(lái)對(duì)跨代引用的標(biāo)記進(jìn)行加速赤嚼。

Card Table,簡(jiǎn)單理解是一種空間換時(shí)間的思路顺又,因?yàn)榇嬖诳绱玫膶?duì)象大概占比不到1%更卒,因此可將堆空間劃分成大小為512字節(jié)的卡頁(yè),如果卡頁(yè)中有一個(gè)對(duì)象存在跨代引用稚照,則可以用1個(gè)字節(jié)來(lái)標(biāo)識(shí)該卡頁(yè)是dirty狀態(tài)蹂空,卡頁(yè)狀態(tài)進(jìn)一步通過(guò)寫(xiě)屏障技術(shù)進(jìn)行維護(hù)。

遍歷完GC Roots后果录,便能夠找出第一批存活的對(duì)象上枕,然后將其拷貝到S1區(qū)。接下來(lái)弱恒,就是一個(gè)遞歸查找和拷貝存活對(duì)象的過(guò)程辨萍。

S1區(qū)為了方便維護(hù)內(nèi)存區(qū)域,引入了兩個(gè)指針變量:_saved_mark_word和_top返弹,其中_saved_mark_word表示當(dāng)前遍歷對(duì)象的位置锈玉,_top表示當(dāng)前可分配內(nèi)存的位置,很顯然义起,_saved_mark_word到_top之間的對(duì)象都是已拷貝但未掃描的對(duì)象拉背。

貝到S1區(qū),_top也會(huì)往前移動(dòng)默终,直到_saved_mark_word追上_top椅棺,說(shuō)明S1區(qū)所有對(duì)象都已經(jīng)遍歷完成。

有一個(gè)細(xì)節(jié)點(diǎn)需要注意的是:拷貝對(duì)象的目標(biāo)空間不一定是S1區(qū)齐蔽,也可能是老年代土陪。如果一個(gè)對(duì)象的年齡(經(jīng)歷的YGC次數(shù))滿(mǎn)足動(dòng)態(tài)年齡判定條件便直接晉升到老年代中。對(duì)象的年齡保存在Java對(duì)象頭的mark word數(shù)據(jù)結(jié)構(gòu)中(如果大家對(duì)Java并發(fā)鎖熟悉肴熏,肯定了解這個(gè)數(shù)據(jù)結(jié)構(gòu),不熟悉的建議查閱資料了解下顷窒,這里不做展開(kāi))蛙吏。

最后的話(huà)

這篇文章通過(guò)線(xiàn)上案例分析并結(jié)合原理講解,詳細(xì)介紹了YGC的相關(guān)知識(shí)鞋吉。從YGC實(shí)戰(zhàn)角度出發(fā)鸦做,再簡(jiǎn)單總結(jié)一下:
1、首先要清楚YGC的執(zhí)行原理谓着,比如年輕代的堆內(nèi)存結(jié)構(gòu)泼诱、Eden區(qū)的內(nèi)存分配機(jī)制、GC Roots掃描赊锚、對(duì)象拷貝過(guò)程等治筒。
2屉栓、YGC的核心步驟是標(biāo)注和復(fù)制,絕部分YGC問(wèn)題都集中在這兩步耸袜,因此可以結(jié)合YGC日志和堆內(nèi)存變化情況逐一排查友多,同時(shí)dump的堆內(nèi)存文件需要仔細(xì)分析。

看完三件事??

如果你覺(jué)得這篇內(nèi)容對(duì)你還蠻有幫助堤框,我想邀請(qǐng)你幫我三個(gè)小忙:

點(diǎn)贊域滥,轉(zhuǎn)發(fā),有你們的 『點(diǎn)贊和評(píng)論』蜈抓,才是我創(chuàng)造的動(dòng)力启绰。

關(guān)注公眾號(hào) 『 java爛豬皮 』,不定期分享原創(chuàng)知識(shí)沟使。

同時(shí)可以期待后續(xù)文章ing??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末委可,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子格带,更是在濱河造成了極大的恐慌撤缴,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叽唱,死亡現(xiàn)場(chǎng)離奇詭異屈呕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)棺亭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)虎眨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人镶摘,你說(shuō)我怎么就攤上這事嗽桩。” “怎么了凄敢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵碌冶,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我涝缝,道長(zhǎng)扑庞,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任拒逮,我火速辦了婚禮罐氨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘滩援。我一直安慰自己栅隐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著租悄,像睡著了一般谨究。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恰矩,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天记盒,我揣著相機(jī)與錄音,去河邊找鬼外傅。 笑死纪吮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萎胰。 我是一名探鬼主播碾盟,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼技竟!你這毒婦竟也來(lái)了冰肴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤榔组,失蹤者是張志新(化名)和其女友劉穎熙尉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搓扯,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡检痰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锨推。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铅歼。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖换可,靈堂內(nèi)的尸體忽然破棺而出椎椰,到底是詐尸還是另有隱情,我是刑警寧澤沾鳄,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布慨飘,位于F島的核電站,受9級(jí)特大地震影響译荞,放射性物質(zhì)發(fā)生泄漏瓤的。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一磁椒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玫芦,春花似錦浆熔、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)慎皱。三九已至,卻和暖如春叶骨,著一層夾襖步出監(jiān)牢的瞬間茫多,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工忽刽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留天揖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓跪帝,卻偏偏與公主長(zhǎng)得像今膊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伞剑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355