Unity性能優(yōu)化經(jīng)驗(yàn)分享【轉(zhuǎn)】

在Unite Copenhagen 2019上捐康,Unity技術(shù)支持工程師Ignacio Liverotti進(jìn)行了一次主題為《性能優(yōu)化經(jīng)驗(yàn)分享》的演講解总,旨在幫助中級(jí)Unity開發(fā)者診斷和解決遇到的性能問題刻盐。

作為Unity EMEA(歐洲隙疚、中東和非洲)地區(qū)的咨詢及開發(fā)團(tuán)隊(duì)的技術(shù)支持工程師供屉。Ignacio Liverotti在大部分時(shí)間中會(huì)和Unity的大客戶進(jìn)行接觸伶丐,幫助他們解決項(xiàng)目中出現(xiàn)的性能問題哗魂。

本文录别,我們將通過此次演講的內(nèi)容葫男,讓你一窺Unity技術(shù)支持工程師的工作內(nèi)容梢褐,并介紹一些優(yōu)化知識(shí)和技巧盈咳,幫助你應(yīng)用到自己的項(xiàng)目中鱼响。

image

《性能優(yōu)化經(jīng)驗(yàn)分享》

《性能優(yōu)化經(jīng)驗(yàn)分享》演講的主要內(nèi)容包括:

  • Unity技術(shù)支持工程師的簡介和核心工作:項(xiàng)目審查。
  • 優(yōu)化和性能分析的介紹桶癣。
  • 針對CPU牙寞、GPU和內(nèi)存使用的優(yōu)化,以及介紹解決問題時(shí)用到的工具和方法惹挟。
  • 一系列通用優(yōu)化原則连锯。
  • Q&A运怖。

項(xiàng)目審查

項(xiàng)目審查是Unity技術(shù)支持工程師的核心工作摇展。我們前往客戶的辦公室咏连,通扯扑螅花上整整兩天時(shí)間來熟悉他們的項(xiàng)目,詢問他們的需求和設(shè)計(jì)決策埠偿,然后使用各種的性能分析工具冠蒋,來檢測性能瓶頸。

在結(jié)構(gòu)完善的項(xiàng)目中斩郎,例如:利用模塊化場景和AssetBundles等功能的項(xiàng)目缩宜,構(gòu)建時(shí)間一般較短锻煌,我們可以在現(xiàn)場優(yōu)化宋梧,然后重新分析場景,確定是否有新的問題跺讯。

此時(shí)優(yōu)化構(gòu)建時(shí)間的重要性就體現(xiàn)出來了:好的優(yōu)化可以實(shí)現(xiàn)更頻繁的迭代刀脏。對于開發(fā)硬件和目標(biāo)硬件之間區(qū)別較大的項(xiàng)目來說耀态,例如:面向移動(dòng)設(shè)備或游戲主機(jī)的項(xiàng)目首装,構(gòu)建時(shí)間的優(yōu)化就更重要了仙逻。

由于我們的客戶非常多樣,他們的項(xiàng)目類型涵蓋了各種目標(biāo)平臺(tái)和需求缺亮,因此項(xiàng)目審查的工作內(nèi)容也不盡相同萌踱。如果在現(xiàn)場工作時(shí)并鸵,我們遇到了沒能解決的問題能真,我們會(huì)盡量收集信息,在回到Unity辦公室后蝙泼,繼續(xù)進(jìn)行進(jìn)一步的調(diào)查汤踏,必要的話還會(huì)咨詢R&D的同事。

最終結(jié)果會(huì)取決于客戶需求哗脖,但通常情況下才避,我們會(huì)提供一份總結(jié)調(diào)查結(jié)果和建議方案的書面報(bào)告棘劣。在決定關(guān)注的重點(diǎn)時(shí)茬暇,我們的目標(biāo)是始終為客戶提供最有價(jià)值的信息。

雖然我們有Unity的源代碼,但在進(jìn)行項(xiàng)目審查時(shí)珊皿,我們會(huì)盡量將自己放在客戶的位置上考慮。也就是說驶兜,我們會(huì)使用網(wǎng)上可找到的性能分析工具和最佳實(shí)踐抄淑,來優(yōu)化客戶的項(xiàng)目。

如果我們需要深入研究來找到性能問題的根本原因郑原,那么在問題解決后犯犁,我們會(huì)盡可能對相關(guān)文檔進(jìn)行更新,從而將這些新知識(shí)提供給所有用戶簇捍,給用戶帶來更大的便利吼句。

CPU綁定與GPU綁定

正如演講里說的惕艳,在開始優(yōu)化項(xiàng)目前,我們需要找出實(shí)際的瓶頸究竟在哪里谁鳍。一個(gè)可行的方法是使用Unity Profiler性能分析器倘潜,來查看CPU的使用狀況。

如下圖所示养泡,如果大部分的幀時(shí)間都用在“Rendering”(渲染)部分,首先我們要確定項(xiàng)目是CPU綁定還是GPU綁定输硝。

image

渲染過程會(huì)同時(shí)在CPU和GPU上執(zhí)行程梦,本文不會(huì)詳細(xì)介紹渲染過程点把,簡單來說,對于共用同一個(gè)材質(zhì)的對象分組屿附,場景的渲染過程主要包含以下步驟:

  • CPU將一系列指令傳遞給GPU郎逃,從而設(shè)置好內(nèi)部狀態(tài),例如:著色器挺份、綁定紋理、頂點(diǎn)格式等部分。該步驟又稱為“set pass(設(shè)置通道)”調(diào)用优训。

  • CPU將幾何體的批處理傳遞給GPU朵你,讓GPU根據(jù)上一步設(shè)置的狀態(tài)來渲染幾何體。這一步稱為“Draw Call(繪制調(diào)用)”揣非,耗費(fèi)性能較大抡医。

  • 如果有更多相同材質(zhì)類型的幾何體需要渲染,那么就重復(fù)第二步操作早敬。

以上操作的相應(yīng)算法有許多的細(xì)節(jié)和注意事項(xiàng)忌傻,但關(guān)鍵點(diǎn)在于渲染過程會(huì)同時(shí)在CPU和GPU上執(zhí)行。如下圖所示搞监,Xcode這類工具可以給我們提供CPU和GPU資源所花的具體時(shí)間水孩。


image

我們也可以在Unity性能分析器找到這類信息,不過由于這些信息取決于顯卡和驅(qū)動(dòng)提供的支持琐驴,因此GPU數(shù)據(jù)不總是會(huì)出現(xiàn)俘种。

image

如果我們無法使用性能分析工具獲取CPU和GPU的使用時(shí)間,則可以在性能分析器中觀察任一幀的情況绝淡。

如果存在對Gfx.WaitForPresent的調(diào)用安疗,并且顯示“調(diào)用花費(fèi)了不少時(shí)間”,這意味著CPU正在等待GPU完成所有的渲染指令够委,說明該項(xiàng)目屬于GPU綁定。

了解WaitForTargetFPS和Gfx.PresentFrame等標(biāo)記的含義:

https://docs.unity3d.com/Manual/ProfilerCPU.html

image

對GPU工作量影響較大的因素有以下幾種:

  • Fill rate(填充率):在特定幀上怖现,應(yīng)用程序多次在過多的像素上進(jìn)行著色茁帽,該過程稱為“Overdraw”(過度繪制)。

  • 內(nèi)存帶寬:應(yīng)用程序可能會(huì)給GPU發(fā)送大量紋理數(shù)據(jù)屈嗤。如果想減少內(nèi)存占用潘拨,我們可以使用紋理圖集來減少紋理數(shù)量,減少紋理大小饶号,或在條件允許時(shí)將紋理壓縮為特定格式铁追。

  • 頂點(diǎn)處理:應(yīng)用程序向GPU發(fā)送過多的幾何體。在Unite的演講中茫船,我們把這種情況作為案例進(jìn)行了講解琅束。

此外,如果項(xiàng)目屬于CPU綁定算谈,那么會(huì)有許多東西會(huì)增加CPU時(shí)間涩禀,例如:物理、游戲代碼等然眼,我們同樣應(yīng)該查看性能分析器艾船。

如果性能分析器告訴我們在渲染上花了很多時(shí)間,這可能表示CPU忙于給GPU傳遞過多的指令。這種情況可以通過減少狀態(tài)變更的次數(shù)(或“SetPass”調(diào)用)和批處理次數(shù)屿岂,來實(shí)現(xiàn)優(yōu)化的目的践宴。

關(guān)于此問題的深入討論,請閱讀《Fixing Performance Problems(修補(bǔ)性能問題)》教程:
https://learn.unity.com/tutorial/fixing-performance-problems#5c7f8528edbc2a002053b596

案例學(xué)習(xí):加載數(shù)據(jù)時(shí)出現(xiàn)CPU峰值情況

在客戶的項(xiàng)目中爷怀,一個(gè)常見問題是:在應(yīng)用程序啟動(dòng)時(shí)阻肩,或進(jìn)入新關(guān)卡的時(shí)候,可能會(huì)出現(xiàn)的性能卡頓問題霉撵。

在Unity性能分析器中磺浙,這類卡頓問題會(huì)顯示為峰值情況。

image

卡頓的原因主要是:性能開銷較大的處理過程和大量的內(nèi)存分配徒坡。在本案例中撕氧,CPU峰值情況造成了近10秒的卡頓,托管分配的內(nèi)存量達(dá)到3.8 GB喇完,如下圖所示伦泥。

image

這種峰值情況應(yīng)該是要避免的,主要有兩個(gè)原因:

  • 過長的運(yùn)算時(shí)間會(huì)中斷應(yīng)用的運(yùn)行過程锦溪。掩蓋卡頓情況的一種方法是使用加載界面不脯,然而如果畫面中需要展示動(dòng)態(tài)元素,那么該方法不會(huì)起到作用刻诊,因?yàn)閯?dòng)畫也會(huì)在加載時(shí)發(fā)生卡頓防楷。

  • 大量的內(nèi)存分配會(huì)造成托管堆的大小永久增大。Unity的自動(dòng)內(nèi)存管理系統(tǒng)的工作方式是:沒有引用的內(nèi)存會(huì)在后續(xù)分配過程中重用则涯,但是托管堆的大小不會(huì)減小复局,而是只會(huì)增加。這種情況稱為“非壓縮式垃圾回收(Non-compacting garbage collection)”粟判。

請參考Unity官方文檔和Unity Learn的文章中了解更多信息亿昏。

Unity官方文檔:
https://docs.unity3d.com/Manual/UnderstandingAutomaticMemoryManagement.html

Unity Learn文章:
https://learn.unity.com/tutorial/fixing-performance-problems#5c7f8528edbc2a002053b595

峰值情況往往由多種因素造成。根據(jù)我們的實(shí)地經(jīng)驗(yàn)档礁,其中一個(gè)原因是應(yīng)用程序使用了未優(yōu)化的格式來存儲(chǔ)數(shù)據(jù)角钩。例如:JSON格式和XML格式,而解析器需要分配大量內(nèi)存來繼續(xù)處理應(yīng)用內(nèi)容呻澜。除了這種分配外递礼,對這類數(shù)據(jù)執(zhí)行的大量計(jì)算和相應(yīng)的內(nèi)存分配都是罪魁禍?zhǔn)住?/p>

為了減小這些問題的影響,我們通常建議客戶實(shí)現(xiàn)“預(yù)算時(shí)間管理器”系統(tǒng)羹幸,它會(huì)在每幀限制中實(shí)例化和初始化對象宰衙,并添加對二進(jìn)制格式的支持《糜“預(yù)算時(shí)間管理器”會(huì)將運(yùn)算分散到多個(gè)幀上供炼,而對二進(jìn)制數(shù)據(jù)的支持則會(huì)減少內(nèi)存分配的大小一屋。

“預(yù)算時(shí)間管理器”與使用單個(gè)方法加載所有數(shù)據(jù)之間的區(qū)別,類似普通垃圾回收器和增量式垃圾回收功能的區(qū)別:前者會(huì)在某一幀上卡頓袋哼,直到整個(gè)列表的托管對象處理完畢冀墨,而后者會(huì)將處理過程分散到多個(gè)幀上執(zhí)行。

由于它們存在的本質(zhì)特點(diǎn)涛贯,二進(jìn)制數(shù)據(jù)通常難以在開發(fā)中使用诽嘉。因此我們建議客戶不要完全移除對文本格式的支持,而是支持和使用文本及二進(jìn)制兩種格式弟翘,具體取決于客戶執(zhí)行的是應(yīng)用程序的開發(fā)版本還是發(fā)布版本虫腋。

垃圾回收過程

在演講的《GC spikes in a fast-paced game”(快節(jié)奏游戲的GC峰值情況》案例中,我們建議客戶啟用Incremental Garbage Collector增量式垃圾回收功能稀余,盡可能減少幀時(shí)間悦冀,給算法足夠的空間在每幀的結(jié)束時(shí)完成執(zhí)行過程。

但在演講中睛琳,沒有足夠強(qiáng)調(diào)的一點(diǎn)是:對于最小化托管內(nèi)存分配的數(shù)量和大小盒蟆,增量式垃圾回收功能不是讓該過程不夠嚴(yán)謹(jǐn)?shù)慕杩凇?/p>

和常規(guī)垃圾回收器相比,增量式垃圾回收優(yōu)點(diǎn)是可以將工作量分布到多個(gè)幀上完成师骗,從而避免在單個(gè)幀上等待整個(gè)托管對象池處理完畢历等,這對維持穩(wěn)定的幀率非常重要。

我們可以把GarbageCollector.GCMode靜態(tài)字段的值更改為GarbageCollector.Mode.Disabled辟癌,從而禁用垃圾回收器寒屯。

GarbageCollector.GCMode =   GarbageCollector.Mode.Disabled;

如果不想產(chǎn)生垃圾回收算法相關(guān)的處理開銷,我們可以使用這個(gè)方法黍少。但需要注意寡夹,使用這種方法時(shí),我們需要確保在垃圾回收器禁用時(shí)仍侥,不會(huì)發(fā)生任何內(nèi)存分配操作。

因?yàn)榫腿缪葜v中所說鸳君,在內(nèi)存使用量超過特定閾值時(shí)污淋,操作系統(tǒng)會(huì)主動(dòng)關(guān)閉應(yīng)用程序忍弛。在Android和iOS等移動(dòng)平臺(tái)上,這種情況更加明顯。

案例學(xué)習(xí):使用權(quán)威服務(wù)器的FPS游戲

權(quán)威服務(wù)器架構(gòu)(Authoritative Server Architecture)危纫,這種架構(gòu)的網(wǎng)絡(luò)游戲是游戲客戶端將輸入(按鍵,命令)發(fā)送到服務(wù)器凌唬,服務(wù)器運(yùn)行游戲缠劝,然后將結(jié)果發(fā)送回客戶端。之所以稱之為“權(quán)威服務(wù)器”平挑,是因?yàn)殛P(guān)于游戲世界中發(fā)生的一切游添,唯一有權(quán)限處理的只有服務(wù)器系草。

幾個(gè)月前我們對一款第一人稱多人射擊游戲進(jìn)行項(xiàng)目審查,該游戲擁有一個(gè)權(quán)威服務(wù)器架構(gòu)唆涝,而服務(wù)器通過無頭模式(Headless mode)運(yùn)行找都。

我們使用了Unity Memory Profiler內(nèi)存分析器來獲取內(nèi)存信息,發(fā)現(xiàn)無頭服務(wù)器上有許多不必要的網(wǎng)格廊酣、光照探針能耻、音頻剪輯、網(wǎng)格渲染器和各種其它類型的對象亡驰,累計(jì)分配了上百M(fèi)B的內(nèi)存晓猛。

雖然這些額外的內(nèi)存占用沒有影響服務(wù)器運(yùn)行單個(gè)多人游戲會(huì)話,但是卻明顯影響到了游戲的可擴(kuò)展性凡辱。具體來說戒职,在特定服務(wù)器上增加活動(dòng)實(shí)例數(shù)量會(huì)需要更多的內(nèi)存。

在這種情況下煞茫,我們建議客戶把每個(gè)游戲關(guān)卡場景分為兩個(gè)部分帕涌,分別保存到不同的AssetBundle中。第一個(gè)部分是“邏輯場景”续徽,其中包含了無頭服務(wù)器需要的所有信息蚓曼,第二個(gè)部分是“可視場景”,其中包含了只有客戶端使用的所有信息钦扭。

這種劃分操作可能會(huì)造成工作流程上的問題纫版。更具體來說,美術(shù)師和關(guān)卡設(shè)計(jì)師將不能在同一個(gè)場景中協(xié)作客情。因此我們沒有讓客戶變更內(nèi)容創(chuàng)作者的工作流程其弊,而是建議保持原有創(chuàng)作流程,在構(gòu)建流程中額外加入劃分為“邏輯場景”和“可視場景”的流程膀斋。

深度分析與分析器標(biāo)記

我們的目標(biāo)是在應(yīng)用程序的核心運(yùn)行循環(huán)中把內(nèi)存分配降到接近0/幀梭伐。減少內(nèi)存分配會(huì)減少垃圾回收算法產(chǎn)生的開銷。

Unity性能分析器是最能勝任的工具仰担,但在調(diào)用堆棧報(bào)告中糊识,默認(rèn)深度層次只能是引擎原生代碼在轉(zhuǎn)入應(yīng)用編程代碼中首次調(diào)用堆棧深度一致,例如:MonoBehaviour.Start()摔蓝、MonoBehaviour. Update()及類似的方法赂苗。

在實(shí)際使用時(shí),如果腳本調(diào)用了其它腳本的方法贮尉,我們無法輕易找到發(fā)生托管內(nèi)存分配的具體位置拌滋。

解決問題的一種方法是:給腳本加上Profiler Markers分析器標(biāo)記。這樣我們可以在性能分析時(shí)記錄額外的信息猜谚,幫助我們縮小內(nèi)存分配的來源范圍败砂。

另一種方法是:啟用Deep Profiling深度分析功能赌渣。

深度分析功能的具體操作請閱讀Unity Learn的文章:
https://learn.unity.com/tutorial/profiling-applications-made-with-unity#5c7f8528edbc2a002053b5b6

請注意,深度分析功能會(huì)增加更多性能開銷吠卷,大幅減慢應(yīng)用運(yùn)行速度锡垄,因此報(bào)告記錄的時(shí)間并不準(zhǔn)確。

我們建議首先在禁用深度分析過程時(shí)祭隔,運(yùn)行性能分析流程货岭,記錄造成額外托管內(nèi)存分配的情況,如果調(diào)用棧報(bào)告不能提供足夠的信息來找出分配來源疾渴,那么我們要使用深度分析功能進(jìn)行第二次分析千贯,從而找到這些分配的來源。

在Unity 2019.3之前搞坝,深度分析功能只可以在使用Mono腳本后端時(shí)使用搔谴。Unity 2019.3的Beta版已經(jīng)不存在這個(gè)限制,深度分析功能同時(shí)支持Mono后端和IL2CPP后端桩撮。

下面是Unity 2019.3 Beta的部分發(fā)行說明:

  • Profiler:添加了Deep Profiler深度分析器對Mono后端和IL2CPP后端的支持敦第。
  • Profiler:添加了Deep Profiling深度分析器對運(yùn)行版本構(gòu)建選項(xiàng)的支持。當(dāng)使用Deep Profiling深度分析功能構(gòu)建運(yùn)行版本時(shí)店量,可以動(dòng)態(tài)地啟用或禁用C#代碼插裝功能(C# Code Instrumentation)芜果。
  • Profiler:對運(yùn)行版本添加了托管內(nèi)存分配調(diào)用棧的支持。當(dāng)啟用調(diào)用椚谑Γ回收時(shí)右钾,GC.Alloc的樣本將包含C#代碼調(diào)用棧。

由于深度分析功能現(xiàn)在支持IL2CPP后端旱爆,開發(fā)者可以在iOS這類只支持IL2CPP的平臺(tái)上執(zhí)行深度分析數(shù)據(jù)收集舀射。此外,新增的對托管內(nèi)存分配調(diào)用棧的支持怀伦,可以幫助開發(fā)者找到運(yùn)行版本內(nèi)存分配來源脆烟,不必進(jìn)行深度分析。

結(jié)語

性能優(yōu)化是一個(gè)很大的話題房待,需要開發(fā)者掌握各式各樣的技能邢羔,例如:了解底層硬件的操作原理和局限。

了解Unity提供的各種類和組件吴攒,算法和數(shù)據(jù)結(jié)構(gòu)张抄,并且要知道如何使用性能分析工具砂蔽,開發(fā)者也需要發(fā)揮一定的創(chuàng)造力洼怔,來找到能夠滿足設(shè)計(jì)需求的高效解決方案。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末左驾,一起剝皮案震驚了整個(gè)濱河市镣隶,隨后出現(xiàn)的幾起案子极谊,更是在濱河造成了極大的恐慌,老刑警劉巖安岂,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件轻猖,死亡現(xiàn)場離奇詭異,居然都是意外死亡域那,警方通過查閱死者的電腦和手機(jī)咙边,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來次员,“玉大人败许,你說我怎么就攤上這事∈缥担” “怎么了市殷?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長刹衫。 經(jīng)常有香客問我醋寝,道長,這世上最難降的妖魔是什么带迟? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任音羞,我火速辦了婚禮,結(jié)果婚禮上邮旷,老公的妹妹穿的比我還像新娘黄选。我一直安慰自己,他們只是感情好婶肩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布办陷。 她就那樣靜靜地躺著,像睡著了一般律歼。 火紅的嫁衣襯著肌膚如雪民镜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天险毁,我揣著相機(jī)與錄音制圈,去河邊找鬼。 笑死畔况,一個(gè)胖子當(dāng)著我的面吹牛鲸鹦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播跷跪,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼馋嗜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吵瞻?” 一聲冷哼從身側(cè)響起葛菇,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤甘磨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后眯停,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體济舆,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年莺债,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滋觉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡齐邦,死狀恐怖椎瘟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侄旬,我是刑警寧澤肺蔚,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站儡羔,受9級(jí)特大地震影響宣羊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜汰蜘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一仇冯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧族操,春花似錦苛坚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至枷莉,卻和暖如春娇昙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背笤妙。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工冒掌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蹲盘。 一個(gè)月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓股毫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親召衔。 傳聞我的和親對象是個(gè)殘疾皇子铃诬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容