數(shù)據(jù)庫(kù)連接池內(nèi)存泄漏

一罩引、問(wèn)題描述

上周三晚上主營(yíng)出現(xiàn)部分設(shè)備掉線了,查看了日志之后發(fā)現(xiàn)是由于緩存system出現(xiàn)長(zhǎng)時(shí)間gc導(dǎo)致的枝笨。這里的gc日志的特征是:

1.gc時(shí)間都在2秒以上袁铐,一部分節(jié)點(diǎn)甚至出現(xiàn)13s超長(zhǎng)時(shí)間gc。

2.同一個(gè)節(jié)點(diǎn)距離上次gc時(shí)間間隔為普遍為12~15天横浑。

隨后緊急把剩余未gc的一個(gè)節(jié)點(diǎn)內(nèi)存dump下來(lái)剔桨,使用mat工具打開(kāi)后發(fā)現(xiàn),com.mysql.jdbc.NonRegisteringDriver 對(duì)象占了堆內(nèi)存的大部分空間徙融。

經(jīng)過(guò)查看對(duì)象數(shù)量洒缀,發(fā)現(xiàn)com.mysql.jdbc.NonRegisteringDriver$ConnectionPhantomReference這個(gè)對(duì)象堆積了10140個(gè)啦

經(jīng)過(guò)判斷長(zhǎng)時(shí)間gc的問(wèn)題是由于 com.mysql.jdbc.NonRegisteringDriver$ConnectionPhantomReference 這個(gè)對(duì)象大量堆積造成的张咳。

二帝洪、問(wèn)題分析

current正式環(huán)境使用數(shù)據(jù)庫(kù)依賴如下面:

依賴版本

mysql5.1.47

hikari2.7.9

Sharding-jdbc3.1.0

根據(jù)以上描述,提出以下問(wèn)題:

1脚猾、com.mysql.jdbc.NonRegisteringDriver$ConnectionPhantomReference 到底是個(gè)啥對(duì)象呢葱峡?

2、這種對(duì)象為什么會(huì)造成大量堆積龙助,JVM回收不過(guò)來(lái)了呢砰奕?

NonRegisteringDriver$ConnectionPhantomReference 到底是個(gè)什么對(duì)象呀?

簡(jiǎn)單來(lái)說(shuō)提鸟,NonRegisteringDriver類(lèi)有個(gè)虛引用集合connectionPhantomRefs用于存儲(chǔ)所有的數(shù)據(jù)庫(kù)連接啊军援,NonRegisteringDriver.trackConnection方法負(fù)責(zé)把新創(chuàng)建的連接放入connectionPhantomRefs集合。源碼如下:

1.public class NonRegisteringDriver implements java.sql.Driver {?

2. ? protected static final ConcurrentHashMap<ConnectionPhantomReference, ConnectionPhantomReference> connectionPhantomRefs = new ConcurrentHashMap<ConnectionPhantomReference, ConnectionPhantomReference>();?

3. ? protected static final ReferenceQueue<ConnectionImpl> refQueue = new ReferenceQueue<ConnectionImpl>();

4. ?

5. ? ? ....?

6. ?

7. ? protected static void trackConnection(Connection newConn) {?

8. ?

9. ? ? ? ConnectionPhantomReference phantomRef = new ConnectionPhantomReference((ConnectionImpl) newConn, refQueue);?

10. ? ? ? ? connectionPhantomRefs.put(phantomRef, phantomRef);?

11. ? }?

12. ? ? ....?

13. }?

我們追蹤創(chuàng)建數(shù)據(jù)庫(kù)連接的中間源碼称勋,發(fā)現(xiàn)其中會(huì)調(diào)到com.mysql.jdbc.ConnectionImpl構(gòu)造函數(shù)胸哥,該方法會(huì)調(diào)用createNewIO方法創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)連接MysqlIO對(duì)象之后,然后調(diào)用我們上面提到的NonRegisteringDriver.trackConnection方法赡鲜,把該對(duì)象放入NonRegisteringDriver.connectionPhantomRefs集合中空厌。源碼如下面:

1.public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLConnection {?

2. ?

3. ? public ConnectionImpl(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url) throws SQLException {?

4. ? ? ? ? ...?

5. ? ? ? createNewIO(false);?

6. ? ? ? ? ...?

7. ? ? ? NonRegisteringDriver.trackConnection(this);?

8. ? ? ? ? ...?

9. ? }?

10.}

connectionPhantomRefs 是一個(gè)虛引用集合,什么是虛引用银酬?為什么設(shè)計(jì)為虛引用隊(duì)列呢

虛引用隊(duì)列也稱為“幽靈引用”嘲更,它是最弱的一種引用關(guān)系。

如果一個(gè)對(duì)象僅持有虛引用揩瞪,那么它就和沒(méi)有任何引用一樣赋朦,在任何時(shí)候都可能被垃 圾回收器回收。

為一個(gè)對(duì)象設(shè)置虛 引用關(guān)聯(lián)的唯一目的只是為了能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。

當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí)宠哄,如果發(fā)現(xiàn)它還有虛引用壹将,就會(huì)在垃圾回收后,將這個(gè)虛引用加入引用隊(duì)列琳拨,在其關(guān)聯(lián)的虛引用出隊(duì)前瞭恰,不會(huì)徹底銷(xiāo)毀該對(duì)象。所以可以通過(guò)檢查引用隊(duì)列中是否有相應(yīng)的虛引用來(lái)判斷對(duì)象是否已經(jīng)被回收了狱庇。

connectionPhantomRefs 這種對(duì)象為啥會(huì)大量堆積,JVM回收不過(guò)來(lái)了么恶耽?

我們先查閱hikaricp數(shù)據(jù)池的官網(wǎng)鏈接地址密任,看看部分屬性介紹如下所示:

maximumPoolSize

This property controls the maximum size that the pool is allowed to reach, including both idle and in-use connections. Basically this value will determine the maximum number of actual connections to the database backend. A reasonable value for this is best determined by your execution environment. When the pool reaches this size, and no idle connections are available, calls to getConnection() will block for up to connectionTimeout milliseconds before timing out. Please read about pool sizing. Default: 10

maximumPoolSize控制最大連接數(shù),默認(rèn)為10

minimumIdle

This property controls the minimum number of idle connections that HikariCP tries to maintain in the pool. If the idle connections dip below this value and total connections in the pool are less than maximumPoolSize, HikariCP will make a best effort to add additional connections quickly and efficiently. However, for maximum performance and responsiveness to spike demands, we recommend not setting this value and instead allowing HikariCP to act as a fixed size connection pool. Default: same as maximumPoolSize

minimumIdle控制最小連接數(shù)偷俭,默認(rèn)等同于maximumPoolSize浪讳,10。

?idleTimeout

This property controls the maximum amount of time that a connection is allowed to sit idle in the pool. This setting only applies when minimumIdle is defined to be less than maximumPoolSize. Idle connections will not be retired once the pool reaches minimumIdle connections. Whether a connection is retired as idle or not is subject to a maximum variation of +30 seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout. A value of 0 means that idle connections are never removed from the pool. The minimum allowed value is 10000ms (10 seconds). Default: 600000 (10 minutes)

連接空閑時(shí)間超過(guò)idleTimeout(默認(rèn)10分鐘)后涌萤,連接會(huì)被拋棄

?maxLifetime

This property controls the maximum lifetime of a connection in the pool. An in-use connection will never be retired, only when it is closed will it then be removed. On a connection-by-connection basis, minor negative attenuation is applied to avoid mass-extinction in the pool. We strongly recommend setting this value, and it should be several seconds shorter than any database or infrastructure imposed connection time limit. A value of 0 indicates no maximum lifetime (infinite lifetime), subject of course to the idleTimeout setting. Default: 1800000 (30 minutes)

連接生存時(shí)間超過(guò) maxLifetime(默認(rèn)30分鐘)后淹遵,連接會(huì)被拋棄.

我們?cè)倩仡^看看項(xiàng)目的hikari配置

配置了minimumIdle = 10,maximumPoolSize = 50负溪,沒(méi)有配置idleTimeout和maxLifetime透揣。所以這兩項(xiàng)會(huì)使用默認(rèn)值 idleTimeout = 10分鐘,maxLifetime = 30分鐘川抡。

也就是說(shuō)假如數(shù)據(jù)庫(kù)連接池已滿辐真,有50個(gè)連接,假如系統(tǒng)空閑崖堤,40個(gè)連接會(huì)在10分鐘后(超過(guò)idleTimeout)被廢棄侍咱;假如系統(tǒng)一直繁忙,50個(gè)連接會(huì)在30分鐘后(超過(guò)maxLifetime)后被廢棄密幔。

猜測(cè)問(wèn)題產(chǎn)生的根源:

每次新建一個(gè)數(shù)據(jù)庫(kù)連接楔脯,都會(huì)把該連接放入connectionPhantomRefs集合中。數(shù)據(jù)連接在空閑時(shí)間超過(guò)idleTimeout或生存時(shí)間超過(guò)maxLifetime后會(huì)被廢棄胯甩,在connectionPhantomRefs集合中等待回收昧廷。因?yàn)檫B接資源一般存活時(shí)間比較久,經(jīng)過(guò)多次Young GC,一般都能存活到老年代蜡豹。如果這個(gè)數(shù)據(jù)庫(kù)連接對(duì)象本身在老年代麸粮,connectionPhantomRefs中的元素就會(huì)一直堆積,直到下次 full gc镜廉。如果等到full gc 的時(shí)候connectionPhantomRefs集合的元素非常多弄诲,該次full gc就會(huì)非常耗時(shí)。

那么怎么解決呢?可以考慮優(yōu)化minimumIdle齐遵、maximumPoolSize寂玲、idleTimeout、maxLifetime這些參數(shù)梗摇,下一小節(jié)我們分析一波

三拓哟、問(wèn)題驗(yàn)證

線上模擬環(huán)境

為了驗(yàn)證問(wèn)題,我們需要模擬線上環(huán)境伶授,調(diào)整maxLifetime等參數(shù)~壓測(cè)思路如下

1.緩存系統(tǒng)模擬線上的配置断序,使用壓測(cè)系統(tǒng)一段時(shí)間內(nèi)持續(xù)壓緩存系統(tǒng),使緩存系統(tǒng)短時(shí)間創(chuàng)建/廢棄大量數(shù)據(jù)庫(kù)連接糜烹,觀察 NonRegisteringDriver 對(duì)象是否如期大量堆積违诗,再手動(dòng)調(diào)用 System.gc() 觀察 NonRegisteringDriver 對(duì)象是否被清理。

2.調(diào)整maxLifetime 參數(shù)疮蹦,觀察相同的壓測(cè)時(shí)間內(nèi) NonRegisteringDriver 對(duì)象是否還發(fā)生堆積诸迟。

這里有以下注意點(diǎn):

1、 要滿足 (gc 間隔時(shí)間 * 新生代進(jìn)入老年代前的存活次數(shù) < maxLifetime)這個(gè)條件愕乎,NonRegisteringDriver 對(duì)象才滿足進(jìn)入老年代的條件阵苇。

2、 minimumIdle = 10感论,maximumPoolSize = 50(minimumIdle和maximumPoolSize和線上配置一致)绅项,idleTimeout設(shè)置10s,maxLifetime設(shè) 100s(gc時(shí)間約20s笛粘,所以要大于 20 * 3 = 60s)趁怔。這樣預(yù)計(jì)在持續(xù)壓測(cè)下每30s就會(huì)產(chǎn)生10個(gè)新連接(就算設(shè)置了maximumPoolSize = 50,這種程序的壓測(cè)10個(gè)連接足以應(yīng)付)

3薪前、 項(xiàng)目?jī)?nèi)存分配小一點(diǎn)润努,以及把新生代進(jìn)入老年代前的存活次數(shù)調(diào)小一點(diǎn),方便新生代的NonRegisteringDriver對(duì)象在較短時(shí)間能進(jìn)入老年代示括,方便在較短時(shí)間觀察到明顯的對(duì)象增長(zhǎng)铺浇。

4、 要監(jiān)測(cè)緩存系統(tǒng)數(shù)據(jù)連接池的連接存活情況垛膝,以及系統(tǒng) gc情況鳍侣。

最終環(huán)境配置如下:

模擬實(shí)驗(yàn)結(jié)果

啟用jvisualvm工具對(duì)緩存系統(tǒng)進(jìn)行實(shí)時(shí)觀察

打開(kāi)hikari相關(guān)debug日志觀察連接池情況

設(shè)置 maxLifetime = 100s,啟動(dòng)緩存系統(tǒng)

確認(rèn)hikari和jvm配置生效

觀察jvisualvm吼拥,發(fā)現(xiàn)產(chǎn)生20個(gè)NonRegisteringDriver 對(duì)象

觀察 hikari日志倚聚,確認(rèn)有20個(gè)連接對(duì)象生成,以及產(chǎn)生總連接10個(gè)凿可,空閑連接10個(gè)惑折。

?初步判斷一個(gè)數(shù)據(jù)庫(kù)連接會(huì)生成兩個(gè) NonRegisteringDriver 對(duì)象授账。

啟動(dòng)壓測(cè)程序,壓測(cè)1000s

期間觀察gc日志惨驶,gc時(shí)間間隔約20s白热,100s后發(fā)生5次 gc

觀察 hikari日志,確認(rèn)有20個(gè)連接對(duì)象生成

觀察jvisualvm變成 40個(gè) NonRegisteringDriver 對(duì)象粗卜,符合預(yù)期屋确。

持續(xù)觀察,1000s后理論上會(huì)產(chǎn)生220個(gè)對(duì)象(20 + 20 * 1000s / 100s)续扔,查看 jvisualvm 如下

產(chǎn)生了240個(gè)對(duì)象攻臀,基本和預(yù)期符合。

實(shí)驗(yàn)結(jié)果分析

再結(jié)合我們生產(chǎn)的問(wèn)題纱昧,假設(shè)我們每天14個(gè)小時(shí)高峰期(12:00 ~ 凌晨2:00)茵烈,期間連接數(shù)20,10個(gè)小時(shí)低峰期砌些,期間連接數(shù)10,每次 full gc 間隔14天加匈,等到下次 full gc 堆積的 NonRegisteringDriver 對(duì)象為 (20 * 14 + 10 * 10) * 2 * 14 = 10640存璃,與問(wèn)題dump里面NonRegisteringDriver對(duì)象的數(shù)量10140 個(gè)基本吻合。

至此問(wèn)題根源已經(jīng)得到完全確認(rèn)5衿础W荻!

四啥寇、問(wèn)題解決方案

由上面分析可知偎球,問(wèn)題產(chǎn)生的廢棄的數(shù)據(jù)庫(kù)連接對(duì)象堆積,最終導(dǎo)致 full gc 時(shí)間過(guò)長(zhǎng)辑甜。所以我們可以從以下方面思考解決方案:

1衰絮、減少?gòu)U棄的數(shù)據(jù)連接對(duì)象的產(chǎn)生和堆積。

2磷醋、優(yōu)化full gc時(shí)間.

【調(diào)整hikari參數(shù)】

我們可以考慮設(shè)置 maxLifetime 為一個(gè)較大的值猫牡,用于延長(zhǎng)連接的生命周期,減少產(chǎn)生被廢棄的數(shù)據(jù)庫(kù)連接的頻率邓线,等到下次 full gc 的時(shí)候需要清理的數(shù)據(jù)庫(kù)連接對(duì)象會(huì)大大減少淌友。

Hikari 推薦 maxLifetime 設(shè)置為比數(shù)據(jù)庫(kù)的 wait_timeout 時(shí)間少 30s 到 1min。如果你使用的是 mysql 數(shù)據(jù)庫(kù)骇陈,可以使用 show global variables like '%timeout%'; 查看 wait_timeout震庭,默認(rèn)為 8 小時(shí)。

下面開(kāi)始驗(yàn)證你雌,設(shè)置maxLifetime = 1小時(shí)器联,其他條件不變。壓測(cè)啟動(dòng)前觀察jvisualvm,NonRegisteringDriver 對(duì)象數(shù)量為20

?1000s主籍,觀察 NonRegisteringDriver 對(duì)象仍然為20

?NonRegisteringDriver 對(duì)象沒(méi)有發(fā)生堆積习贫,問(wèn)題得到解決。

同時(shí)另外注意:minimumIdle和maximumPoolSize不要設(shè)置得太大千元,一般來(lái)說(shuō)配置minimumIdle=10苫昌,maximumPoolSize=10~20即可。

【使用G1回收器】

G1回收器是目前java垃圾回收器的最新成果幸海,是一款低延遲高吞吐的優(yōu)秀回收器祟身,用戶可以自定義最大暫停時(shí)間目標(biāo),G1會(huì)盡可能在達(dá)到高吞吐量同時(shí)滿足垃圾收集暫停時(shí)間目標(biāo)物独。

下面開(kāi)始驗(yàn)證G1回收器的實(shí)用性袜硫,該驗(yàn)證過(guò)程需要一段較長(zhǎng)時(shí)間的觀察,同時(shí)借助鏈路追蹤工具skywalking挡篓。最終觀察了10天婉陷,結(jié)果圖如下: 使用G1回收器,部分jvm參數(shù)-Xms3G -Xmx3G -XX:+UseG1GC

使用java 8默認(rèn)的Parallel GC回收器組合官研,部分jvm參數(shù)-Xms3G -Xmx3G

以上圖中四個(gè)內(nèi)容秽澳,從左到右分別為

1、堆內(nèi)存戏羽,分為已使用和空閑內(nèi)存担神。

2、方法區(qū)內(nèi)存始花,這個(gè)不需要關(guān)注

3妄讯、young gc和full gc時(shí)間

4、程序啟動(dòng)以后young gc和full gc次數(shù)

我們可以看到使用Parallel GC回收器組合的服務(wù)消耗的內(nèi)存速度較快酷宵,發(fā)生了6996次young gc且發(fā)生了一次full gc亥贸,full gc時(shí)間長(zhǎng)達(dá)5s。另外一組使用G1回收器的服務(wù)消耗內(nèi)存速度較為平穩(wěn)忧吟,只發(fā)生3827次young gc且沒(méi)有發(fā)生full gc砌函。由此可以看到G1回收器確實(shí)可以用來(lái)解決我們的數(shù)據(jù)庫(kù)連接對(duì)象堆積問(wèn)題。

【建立巡查系統(tǒng)】

這個(gè)我們目前還沒(méi)有經(jīng)過(guò)實(shí)踐溜族,但是根據(jù)上面分析結(jié)果判斷讹俊,定期觸發(fā)full gc可以達(dá)到每次清理少量堆積的數(shù)據(jù)庫(kù)連接的作用,避免過(guò)多數(shù)據(jù)庫(kù)連接一直堆積煌抒。采用該方法需要對(duì)業(yè)務(wù)的內(nèi)容和高低峰周期非常熟悉仍劈。實(shí)現(xiàn)思路參考如下:

1、創(chuàng)建java程序寡壮,使用定時(shí)任務(wù)定期調(diào)用System.gc()贩疙。該方法的缺點(diǎn)是即使手動(dòng)調(diào)用了System.gc()讹弯,jvm不一定會(huì)立刻開(kāi)始回收工作,有可能會(huì)根據(jù)它本身的算法这溅,自行選擇最優(yōu)時(shí)間才開(kāi)始進(jìn)行回收工作组民。

2、創(chuàng)建shell腳本調(diào)用jmap -dump:live,file=dump_001.bin PID悲靴,使用linux的crontab任務(wù)保證定時(shí)執(zhí)行臭胜,執(zhí)行完后再把dump_001.bin刪掉即可。該方法能保證一定發(fā)生full gc癞尚,缺點(diǎn)是功能過(guò)于單一零散耸三,不好集中管理。

五浇揩、總結(jié)

我們這次問(wèn)題產(chǎn)生的根源是數(shù)據(jù)庫(kù)連接對(duì)象堆積仪壮,導(dǎo)致full gc時(shí)間過(guò)長(zhǎng)。解決思路可以從以下三點(diǎn)入手:

1胳徽、調(diào)整hikari配置參數(shù)积锅。例如把maxLifetime設(shè)置為較大的值(比數(shù)據(jù)庫(kù)的wait_timeout少30s),minimumIdle和maximumPoolSize值不能設(shè)置太大养盗,或者直接采用默認(rèn)值即可乏沸。

2、采用G1垃圾回收器爪瓜。

3、建立巡查系統(tǒng)匙瘪,在業(yè)務(wù)低峰期主動(dòng)觸發(fā)full gc铆铆。

個(gè)人公眾號(hào)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市丹喻,隨后出現(xiàn)的幾起案子薄货,更是在濱河造成了極大的恐慌,老刑警劉巖碍论,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谅猾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鳍悠,警方通過(guò)查閱死者的電腦和手機(jī)税娜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)藏研,“玉大人敬矩,你說(shuō)我怎么就攤上這事〈赖玻” “怎么了弧岳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵凳忙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我禽炬,道長(zhǎng)涧卵,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任腹尖,我火速辦了婚禮柳恐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘桐臊。我一直安慰自己胎撤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布断凶。 她就那樣靜靜地躺著伤提,像睡著了一般。 火紅的嫁衣襯著肌膚如雪认烁。 梳的紋絲不亂的頭發(fā)上肿男,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音却嗡,去河邊找鬼舶沛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛窗价,可吹牛的內(nèi)容都是我干的如庭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼撼港,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坪它!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起帝牡,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤往毡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后靶溜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體开瞭,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年罩息,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗤详。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓷炮,死狀恐怖断楷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情崭别,我是刑警寧澤冬筒,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布恐锣,位于F島的核電站,受9級(jí)特大地震影響舞痰,放射性物質(zhì)發(fā)生泄漏土榴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一响牛、第九天 我趴在偏房一處隱蔽的房頂上張望玷禽。 院中可真熱鬧,春花似錦呀打、人聲如沸矢赁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)撩银。三九已至,卻和暖如春豺憔,著一層夾襖步出監(jiān)牢的瞬間额获,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工恭应, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抄邀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓昼榛,卻偏偏與公主長(zhǎng)得像境肾,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胆屿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355