JAVA GUI 监控工具 JConsole,Jmc,VisualVm,JProfiler

现实企业级 Java 开发中,有时候我们会碰到下面这些问题:
OutOfMemoryError,内存不足
内存泄露
线程死锁
锁争用(Lock Contention)
Java 进程消耗 CPU 过高

jvm 有着非常棒的小块内存虚拟化技术,这会让你产生一种拥有无限内存的错觉感,其实它的开销非常大。有时候jvm 需要找出此刻堆上数据是如何被使用的,并把剩余的空间扩大——这就是垃圾回收。产生这种情况的原因是,jvm 实际获得的物理内存是有限的,因此需要在不被使用时进行内存回收和复用。在一
些时间敏感的应用中,比如交易系统和通信程序,这些暂停是不能容忍的。有很多 GC 调优方法可以避免这种暂停发生。貌似上面的讨论已经跑题了。让 GC 变少的
方法当然是尽量减少分配内存。

有时候,你希望找出在你的程序中哪些地方导致了内存分配的压力。引起这种压力的原因有很多种。最普通的一种情况可能是jvm需要经常GC,并且时间远超过你认为的合理值。

这些问题在日常开发中可能被很多人忽视(比如有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),跟踪 Java 应用程序瓶颈来源一直以来都是很麻烦的。当应用程序性能受到损害时,我们必须要通过一些方法来定位问题的所在,剔除安全隐患,下面就介绍一些可以帮助我我们监控 Java 信息图形化工具。

JAVA.png

一、JConsole

1、简介

JConsole 是一个内置 Java 性能分析器,可以从命令行或在 GUI shell 中运行,从 Java 5 开始 引入了 JConsole。您可以轻松地使用 JConsole、来监控 Java 应用程序性能和跟踪 Java 中的代码。

使 JDK 在 PATH 上,运行 jconsole 即可。当分析工具弹出时(取决于正在运行的 Java 版本以及正在运行的 Java 程序数量),可能会出现一个对话框,要求输入一个进程的 URL 来连接,也可能列出许多不同的本地 Java 进程(有时包含 JConsole 进程本身)来连接。如图所示:

JConsle1.png

想分析哪个程序就双击哪个进程,然后选择”insercure“就会连接上了。

2、设置 JAVA 程序运行时可以被 JConsolse 连接分析

本地程序(相对于开启JConsole的计算机),无需设置任何参数就可以被本地开启的JConsole连接(Java SE 6开始无需设置,之前还是需要设置运行时参数 -Dcom.sun.management.jmxremote ,启动 JMX 服务)
无认证连接 (下面的设置表示:连接的端口为8099、无需认证就可以被连接)

|

1

2

3

4

5

|

-Dcom.sun.management.jmxremote \

-Dcom.sun.management.jmxremote.port=8099 \

-Dcom.sun.management.jmxremote.authenticate=``false \

-Dcom.sun.management.jmxremote.ssl=``false \

-Djava.rmi.server.``hostname``=IP

|

JMX:Java Management Extensions ,即 Java 管理扩展 , 是一个为应用程序、设备、系统等植入管理功能的框架。 JMX 可以跨越一系列异构操作系统平台、系统体系结构和 网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用 。

-Dcom.sun.management.jmxremote 可以不加,默认值是 ture;

-Dcom.sun.management.jmxremote.port 是端口号,随便设置一个就可以了;

-Dcom.sun.management.jmxremote.ssl 是否启动 ssl 连接,默认值是 true,没有配置ssl证书就设置为 false 也可是访问;

-Dcom.sun.management.jmxremote.authenticate 是否启动身份验证,默认值是 true,默认的验证文件在 ${JAVA_HOME}/jre/lib/management/ 下,可以用 -Dcom.sun.management.jmxremote. access.file 与 -Dcom.sun.management.jmxremote. password.file 来指定配置用户访问权限文件与配置用户信息的文件位置(包括用户名和密码),如果不需要配置访问用户名及密码,设置为 false 就可以了,

jmxremote.access 、jmxremote.password 这个文件最小权限要设置为 600,组和其它用户没有任何权限,否则会禁止访问;

-Djava.rmi.server.hostname 该选项是设置访问地址的,必须设置,设置为本机 IP 或 主机名,如果设置为 127.0.0.1,那么远程主机就无法访问了。

详细的安全设置参数,请参考:http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html#gden

3、JConsole 如何连接远程机器的 JAVA 程序

|

1

2

3

4

5

6

7

8

9

10

|

用法: jconsole [ -interval=n ] [ -notile ] [ -pluginpath <path> ] [ -version ] [ connection ... ]

-interval 将更新间隔设置为 n 秒 (默认值为 4 秒)

-notile 初始不平铺窗口 (对于两个或多个连接)

-pluginpath 指定 jconsole 用于查找插件的路径

-version 输出程序版本

connection = pid || host:port || JMX URL (service:jmx:<协议>:``//``...)

pid 目标进程的进程 ID

host 远程主机名或 IP 地址

port 远程连接的端口号

-J 指定运行 jconsole 的 Java 虚拟机的输入参数

|

写一个简单的一直运行的 Java 程序,运行在某台机器上如 (172.16.100.253),也可用 Tomcat 测试

|

1

|

java -``cp . -Dcom.sun.management.jmxremote.port=8099 -Dcom.sun.managent.jmxremote.authenticate=``false -Dcom.sun.management.jmxremote.ssl=``false -Djava.rmi.server.``hostname``=172.16.100.253 JConsoleTest

|

在另外一台机器上进行连接,也可以直接使用命令:

|

1

|

jconsole 172.16.100.253:8099

|

也可以在已经打开的 JConsole 界面操作 连接->新建连接->选择远程进程->输入远程主机IP和端口号->点击“连接”,如图:

JConsle2.png

然后就会进入分析界面

(1)性能分析

下面说说如何分析,如何使用这六个标签

Overview(概述): Displays overview information about the Java VM and monitored values.
Memory(内存): 显示内存使用信息
Threads(线程): 显示线程使用信息
Classes(类): 显示类装载信息
VM Sumary(VM摘要):显示java VM信息
MBeans: 显示 MBeans.

(2)概述

JConsle3.png

概述中将各个时间资源使用情况绘制成图表显示,不过值得一提的是对着图点击右键可以保存数据到 CSV 文件,所有图都可以导成 CVS 文件,以后可以使用其他工具来分析这些数据,。

(3)内存

JConsle4.png

这个比较有价值,参看堆内存,非堆内存,内存池的状况总体内存的分配和使用情况以及不同的 GC 进行垃圾回收的次数和时间。可以手动进行 GC 查看内存变化。在分析 JAVA 内存问题进行调优时候非常有用,你要学习 JVM 内存模型,之后会发现这里的每个值都具有意义。 GC 的算法和参数对性能有显著的影响,注意垃圾回收次数、时间、以及 partial GC 和 full GC,调整你所使用的不同 GC 和以及各个 GC 下的参数,然后在这个视图下观察,以得到好的性能。
这里贴一下 Java HotSpot VM garbage collector 下generational GC 的各代的划分图:

GC.png

关于GC,可以参考:http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html

(4)线程

JConsle5.png

左下角显示所有的活动线程(如果线程过多,可以在下面的过滤栏中输入字符串过滤出你想要观察的线程)。点击某个显示会显示这个线程的名称、状态、阻塞和等待的次数、堆栈的信息。
统计图显示的是线程数目的峰值(红色)和当前活动的线程(蓝色)。
另外下面有个按钮“检测到死锁”,有时候会有用处。

(5)类

JConsle6.png

这个没什么可解释的了。

(6)VM摘要

JConsle7.png

这里可以看到,操作系统,内存,线程等全部信息,方便我们调整系统资源的分配。

(7)MBean

JConsle8.png

这里可以有一些额外的操作,方便调试代码。

(8)插件

|

1

|

jconsole -pluginpath ``/usr/local/jdk1``.7.0_79``/demo/management/JTop/JTop``.jar

|

JConsle9.png

|

1

|

JTop 插件在 JDK 的 demo 包中,还有许多其它的样例,该插件的功能一目了然。

|

二、Jmc

1、简介

Oracle 发布了 Java 7 update 40,该修订版增加了一些重要的新特性,包括 JVM 监控工具、任务控制,Java applet 规则集、Web Start 应用程序以及大量的 bug 修复。新增的一个非常好用的工具,就是 Java Mission Control(JMC 任务控制工具) 。 JRockit Misson Control 用户应该会对 mission control 的很多功能十分熟悉,JRockit 也是一款很棒的工具。Java 任务控制(JMC)是一个产品时间工具套件,它的根源是 JRockit JVM 工具。该工具套件的目的是提供不张扬的 Java 监控和管理,适合在开发和产品环境中使用。JMC 与 Java Flight Recorder 一起工作,适用于 HotSpot JVM,用来记录核心数据和事件。它是一个调优工具,一旦出现问题,这些数据就可以用来分析。

该工具套件由三个主要的组件组成:Java 进程浏览器、JMX 控制台和 Java Flight 记录器。
Java 进程浏览器:允许用户列出并连接到本地和远程运行的Java应用程序。它能够使用 Java发现协议(JDP)自动地发现本地和远程运行的 Java 进程。
JMX 控制台:能够通过 JMX 接口管理并监控 JDK。它提供了实时集合、堆使用情况、CPU 负载以及其他通过 MBeans 暴露的和在 MBean 服务器中注册的信息。
Java Flight 记录器:提供了一种从操作系统层、JVM 和 Java 应用程序层收集事件的方式。收集的事件包括线程延时事件,例如休眠(sleep)、等待(wait)、锁竞争、I/O、GC 和方法分析。Oracle 估计对大多数应用程序而言运行 Flight 记录器的性能开销大约在 2% 左右。

2、Jmc 使用方法

打开以后界面如下:

Jmc1.png

Jmc 既可以连接本地 Java 程序,也可以连接本地 Java 程序,远端要开启 jmxremote 访问。本地程序在左侧想查看的的程序名那里,右键点击启动 JMX 控制台就可以了。远程访问在左侧空白处右键点击新建连接,如图填写好主机和端口,这里的主机和端口就是我们前面在远程服务器配置的服务器 IP 和端口。

Jmc2.png
Jmc3.png

创建完成之后我们就能看到服务器的概要信息了。通过下面的选项卡就可以切换显示其它的详细的信息了。

概览:

Jmc4.png

MBean 浏览器:

Jmc5.png

触发器:

Jmc6.png

系统:

Jmc7.png

内存:

Jmc8.png

线程:

Jmc9.png

诊断命令:

Jmc10.png

Jmc 还可以安装一些插件,增加一些功能。所有的功能都可以点击右上角的 "? " ,会通过浏览器访问本地的帮助文件。

飞行记录器使用前,需要在 Java 程序启动前加 2 个参数“ -XX:+UnlockCommercialFeatures -XX:+FlightRecorder ”,如果没有添加,无法使用飞行记录器飞行记录器启动后,可以记录服务器一段时间内的运行状况,还可导成文件备份,需要 Java 程序启动前在加一个参数“ -XX:FlightRecorderOptions=defaultrecording=true”才可以导出,方便随时分析,这个是查找服务器性能的利器。

Jmc11.png

飞行记录器记录成功之后可以看到下面的一些信息:

Jmc12.png

Jmc 很丰富、很强大,其他功能可以自行研究。

三、VisualVm

1、简介

VisualVM 是 Netbeans 的 profile 子项目,自从JDK 6 Update 7以后已经作为JDK的一部分(java启动时不需要特定参数,监控工具为在${JAVA_HOME}/bin/jvisualvm),是一款免费的Java虚拟机监控和性能分析工具。能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。

jvisualvm 从界面上看还是比较简洁的,左边是树形结构,自动显示当前本机所运行的 Java 程序,还可以添加远程的 Java VM,其中括号里面的 PID 指的是进程 ID。OverView 界面显示 VM 启动参数以及该 VM 对应的一些属性。Monitor 界面则是监控 Java 堆大小,Permgen 大小,Classes 和线程数量。

该工具提供了一个图形界面窗口,并且可以直观的了解Java应用程序的运行时信息。jvisualvm 集成了许多工具,比如像 jmp、jinfo、jstat、jstack、JConsole 等。它通过 jvmstat、JMX、SA(Serviceability Agent)以及 Attach API 等多种方式从程序运行时获得实时数据,从而进行动态的性能分析。同时,它能自动选择更快更轻量级的技术尽量减少性能分析对应用程序造成的影响,提高性能分析的精度。

2、安装插件并启动 Java VisualVM

配置好 JDK 环境变量,执行 jvisualvm 就可以打开软件了,在 VisualVM 插件中心安装插件安装步骤如下 :
从主菜单中选择“工具”>“插件”,在“可用插件”标签中,选中该插件的“安装”复选框。单击“安装”,逐步完成插件安装程序。这些插件都是 .nbm 文件,也可以提前下好,在已下载标签中点击“添加插件按钮”,选择已下载的插件文件 (.nbm) 并打开,逐步完成插件安装程序。

VisualVM1.png

安装好插件后,相应的功能就可以使用了。

3、通过 Java VisualVM 连接到服务器监控 Java 程序

监控本地进程,双击左侧本地下边的进程名字就可以查看监控信息了。

接下来就是远程监控 Java 程序了,默认是使用 Jstatd 连接到远程主机的,所以在远程主机上,必须要一直运行着 jstatd 守护程序,启动方法可以参考上一篇文章。

右键点击远程-添加远程主机-输入主机ip地址,确认提交后即可看到相应的远程主机和在上面运行的 Java 程序,连接成功后应该会显示 Jstatd 及其 PID。

VisualVM2.png

通过以上方式连接服务器发现一个问题,不能监控 CPU ,提示不受此 JVM 支持,所以我们还是要使用 JMX 方式来连接远程主机,如果远端服务开启了 JMX,只需在远程主机那里右键添加一个 JMX 连接就可以了。连接成功,现在我们可以远程监控服务器性能。

VisualVM3.png
VisualVM4.png

在上图中可以看到cpu利用率和垃圾回收活动(这个在分析tomcat性能时也很重要)。然后是堆栈使用情况。下面是类的使用情况,最后一个是线程活动情况。

点击线程标签可以看到:

VisualVM5.png

上图可以非常清晰的看到线程活动情况,那些线程正在执行,哪些线程正在等待中,以及执行完毕的线程等。JDK 1.7 中的这个工具线程监控页面功能减少了,只剩时间线了(Timeline),JDK 1.6 内置的工具,还表(tab)、详细信息(Details)功能,可以右键选择查看单个进程的详细的状态信息。部分监控页还可以 Dump 出来状态文件保存下来,然后分析,如将 Heap Dump 出的远程文件 *.hprof ,拷贝到本地导入后分析。

加载后的 Dump 分析:

VisualVM6.png

这可是一个性能分析利器哦!暂时就介绍这些功能。

四、JProfiler

1、简介

JProfiler 是一个商业授权的 Java 剖析工具,主要用于检查和跟踪系统(限于Java开发的)的性能的工具,它是德国 ej-technologies 公司开发的一款全功能的 Java 剖析工具(profiler),专用于分析 J2SE 和 J2EE 应用程序。它把CPU、执行绪和内存的剖析组合在一个强大的应用中。 JProfiler 可提供许多 IDE 整合和应用服务器整合用途。JProfiler 直觉式的 GUI 让你可以找到效能瓶颈、抓出内存漏失(memory leaks)、并解决执行绪的问题。它让你得以对 heap walker 作资源回收器的 root analysis,可以轻易找出内存漏失;heap 快照(snapshot)模式让未被参照(reference)的对象、稍微被参照的对象、或在终结(finalization)队列的对象都会被移除;整合精灵以便剖析浏览器的 Java 外挂功能。

2、安装

下载地址:http://www.ej-technologies.com/download/jprofiler/files 目前最新版是 Version: 9.0.3 (2015-09-16)

这里使用 Version:8.0.7 版本来演示安装,低版本的功能已经满足我的的需求了,而且也破解也方便。对与 Linux 系统,官网提供了 3 种 安装文件,分别是 Setup Executable、RPM 和 TAR.GZ,我这里下载的是 Setup Executable 版本,直接执行就可以安装了。

|

1

2

3

|

wget http:``//download-aws``.ej-technologies.com``/jprofiler/jprofiler_linux_8_0_7``.sh

chmod +x jprofiler_linux_8_0_7.sh

.``/jprofiler_linux_8_0_7``.sh -c

|

按照提示来安装就可以了,提示都很简单,不在多说,默认安装路径在 /opt/jprofiler8 下。

注意,这里的 -c 意思是用字符方式来安装,默认是以图形化方式安装的。

3、配置使用

(1)运行 JProfiler,第一次打开会有向导,忽略它;

JProfiler1.png

(2)选择 Session->Integration Wizard->New Remote Integratation;

也可以选择其它几个连接方式也可以,按照向导一步一步操作就可以了。

JProfiler2.png

(3) 选择 On a remote computer;Platform of remote computer 选择 Linux x86/AMD 64;

JProfiler3.png

(4)选择服务器的 JDK 环境,这里是:Sun,1.7.0,hotspot;

服务器上可能安装了多个 JAVA 版本,所选的 JVM 提供商和版本,一定要选应用程序启动时所用的。

JProfiler4.png

(5)选择启动模式:这里选第一种 wait for a connection from the jprofiler GUI;

JProfiler5.png

关于上边显示的3个选项做一下说明:

Wait for a connection from the Jprofiler GUI,此模式为,在启动 Java 程序时,需要等 Jprofiler 连接后才能启动,开发人员经常使用此项;

Startup immediately,connect later with the JProfiler GUI,此模式下, Java 程序独立启动,Jprofiler 随时可以连接;

Profile offline,JProfiler GUI cannot connect,此模式为离线模式,生成相关记录文件事后分析;

(6)输入远程服务器 IP;

JProfiler6.png

(7)输入远程服务器上的 JProfiler 的安装路径,如 /opt/jprofiler8;

在连接远程机器时,远程机器也是需要安装 JProfiler 的,2个 JProfiler 版本要保持一致。

JProfiler7.png

(8)会提示 JProfiler 的端口,默认是 8849,可以不用修改,直接下一步就可以了;

JProfiler8.png

(9)这里会列出需要在服务器端做的配置;

JProfiler9.png

将上述参数 -agentpath:/opt/jprofiler8/bin/linux-x64/libjprofilerti.so=port=8849 添加到远程主机的启动参数中,如监控 Tomcat 服务,添加到 $CATALINA_OPTS 中,启动服务时,在日志中可以看到,系统会一直处于等待状态,直到 JProfiler 连接上Tomcat,程序才会继续进行。

|

1

2

3

4

5

6

7

8

9

10

11

|

JProfiler> Protocol version 39

JProfiler> Using JVMTI

JProfiler> JVMTI version 1.1 detected.

JProfiler> 64-bit library

JProfiler> Listening on port: 8849.

JProfiler> Instrumenting native methods.

JProfiler> Can retransform classes.

JProfiler> Can retransform any class.

JProfiler> Native library initialized

JProfiler> VM initialized

JProfiler> Waiting ``for a connection from the JProfiler GUI ...

|

(10)启动 JProfiler 查看监控数据

点击 JProfiler 菜单 session>start center>Open Session

Available session configurations中列出了刚才配置的连接,选中使用就OK了!

Initial Profiling Settings 选择默认的,一般我们都是要查看所有项。

JProfiler10.png
JProfiler11.png
JProfiler12.png
JProfiler13.png

JProfiler 可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视 JVM 运行情况及其性能。

4、破解注册

JProfiler8 注册码序列号

按默认选择“Single or evaluation license”

Name 和 Company 随意
————————————————————–
L-Larry_Lau@163.com#23874-hrwpdp1sh1wrn#0620
L-Larry_Lau@163.com#36573-fdkscp15axjj6#25257
L-Larry_Lau@163.com#5481-ucjn4a16rvd98#6038
L-Larry_Lau@163.com#99016-hli5ay1ylizjj#27215
L-Larry_Lau@163.com#40775-3wle0g1uin5c1#0674
————————————————————–
L-Larry_Lau@163.com#7009-14frku31ynzpfr#20176
L-Larry_Lau@163.com#49604-1jfe58we9gyb6#5814
L-Larry_Lau@163.com#25531-1qcev4yintqkj#23927
L-Larry_Lau@163.com#96496-1qsu1lb1jz7g8w#23479
L-Larry_Lau@163.com#20948-11amlvg181cw0p#171159

注册码前面的邮箱部分为注册邮箱,破解后,就不限制使用时间了。

5、IDE 集成

JProfiler 还可以和 IDE 工具集成,边调试代码,边查看系统运行情况。当 JProfiler 与 IDE (eclipse)集成后,不需要配session,可以直接在 IDE 中调用。安装前关闭 eclipse,按照安装向导进行就可以了。

JProfiler 监控要占用一定的系统资源,所以一般情况下不要用于性能测试。实际操作中,最好有开发人员来观察分析视图,跟踪具体的代码问题,从而针对性的修改某部分代码,优化程序。JProfiler 功能很多,这里就不细说了,在使用过程中,一点一点摸索吧。

转自:http://blog.chopmoon.com/favorites/226.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容