提交 bbec2994 编写于 作者: W wizardforcel

2021-05-12 21:41:16

上级 c6093bbf
......@@ -571,7 +571,7 @@ public class DependencyTest {
正如您在本章前面所读到的,大多数内部 API 都是强封装的。如前所述,在更新源代码时,您可能会寻找替换 API。当然,这并不总是可行的。您可以在运行时使用`--add-opens`选项、使用`--add-exports`选项和`--permit-illegal-access`命令行选项来采取另外三种方法。让我们看看每一个选项。
# --add 打开选项
# `--add-opens`选项
您可以使用`--add-opens`运行时选项来允许您的代码访问非公共成员。这可以称为**深反射**。进行这种深度反思的图书馆能够访问所有成员,包括私人和公共。要授予这种类型的代码访问权限,可以使用`--add-opens`选项。语法如下:
......@@ -581,7 +581,7 @@ public class DependencyTest {
这允许给定的模块打开指定的包。使用此选项时,编译器不会产生任何错误或警告。
# --add exports 选项
# `--add-exports`选项
您可以使用`--add-exports`来破坏封装,这样您就可以使用默认为不可访问的内部 API。语法如下:
......@@ -599,7 +599,7 @@ public class DependencyTest {
只有在认为绝对必要的情况下才应使用`--add-exports`命令行选项。除短期解决方案外,不建议使用此选项。常规使用它的危险在于,对引用的内部 API 的任何更新都可能导致代码无法正常工作。
# --permit 非法访问选项
# `--permit-illegal-access`选项
打破封装的第三个选择是使用`--permit-illegal-access`选项。当然,谨慎的做法是与第三方库创建者核实是否有更新的版本。如果这不是一个选项,那么您可以使用`--permit-illegal-access`非法访问要在类路径上实现的操作。由于这里的操作非常非法,每次发生这些操作时,您都会收到警告。
......@@ -707,7 +707,7 @@ Java 中删除的另外两个内容如下:
# 序列化小程序
Java 不再支持将 Applet 作为序列化对象进行部署。过去,applet 被部署为序列化对象,以补偿压缩速度慢和 JVM 性能问题。在当前的 Java 平台上,压缩技术是先进的,JVM 具有良好的性能。
Java 不再支持将 Applet 作为序列化对象进行部署。过去,Applet 被部署为序列化对象,以补偿压缩速度慢和 JVM 性能问题。在当前的 Java 平台上,压缩技术是先进的,JVM 具有良好的性能。
如果尝试将小程序部署为序列化对象,则在启动小程序时,对象属性和参数标记将被忽略。从 Java9 开始,您可以使用标准部署策略部署小程序。
......@@ -721,7 +721,7 @@ JNLP 规范在 Java9 中进行了更新。以下章节详细介绍了四个具
# 嵌套资源
以前支持将组件扩展与 Java 或 j2se 元素中的嵌套资源一起使用,但规范中没有对此进行说明。规范现在已经更新以反映这种支持。先前的规范如下:
以前支持将组件扩展与 Java 或 J2SE 元素中的嵌套资源一起使用,但规范中没有对此进行说明。规范现在已经更新以反映这种支持。先前的规范如下:
*不能将 Java 元素指定为资源的一部分。*
......@@ -729,7 +729,7 @@ JNLP 规范在 Java9 中进行了更新。以下章节详细介绍了四个具
组件扩展中的 Java 元素不会控制所使用的 Java 版本,但可以使用包含嵌套资源元素的 Java 版本,并且只有在使用与第 4.6 节中指定的给定版本匹配的 Java 版本时,才可以使用这些资源。
这个特定的更改确保扩展 JLP 文件必须具有 Java 或 j2se 资源,并且这些资源不会指定使用什么 JRE。使用指定版本时允许嵌套资源。
这个特定的更改确保扩展 JLP 文件必须具有 Java 或 J2SE 资源,并且这些资源不会指定使用什么 JRE。使用指定版本时允许嵌套资源。
# FX XML 扩展
......@@ -904,7 +904,7 @@ Maven 可以与 Eclipse(M2Eclipse)、JetBrains IntelliJ IDEA 和 netbeansIDE
* 您可以很容易地解析 Maven 依赖关系(您可以直接从 Eclipse 执行此操作,而不必安装本地 Maven 存储库)
* 您可以自动下载所需的依赖项(从远程 Maven 存储库)
* 您可以使用软件向导创建新的 Maven 项目,创建`pom.xml`文件,并为普通 Java 项目启用 Maven 支持
* Use 可以对 Maven 的远程存储库执行快速的依赖性搜索
* 可以对 Maven 的远程存储库执行快速的依赖性搜索
# 获取 Eclipse IDE
......
......@@ -65,7 +65,7 @@ jshell <options> <load files>
| `/edit` | 使用此命令,您可以使用`name``id`引用编辑源条目语法如下:`/edit <name or id>` |
| `/env` | 这个强大的命令允许您查看或更改评估上下文语法如下:`/env [-class-path <path>]  [-module-path <path>]  [-add-modules <modules>]` |
| `/exit` | 此命令用于退出 JShell。语法是简单的`/exit`,没有任何可用的选项或参数。 |
| `/history` | history 命令提供您所键入内容的历史记录。语法是简单的`/history`,没有任何可用的选项或参数。 |
| `/history` | `history`命令提供您所键入内容的历史记录。语法是简单的`/history`,没有任何可用的选项或参数。 |
| `/<id>` | 此命令用于通过引用`id`重新运行以前的代码段。语法如下:`/<id>`您也可以使用`/-<n>`引用前`n`个代码段来运行特定的代码段。 |
| `/imports` | 可以使用此命令列出导入的项目。语法为`/imports`,不接受任何选项或参数。 |
| `/list` | 此命令将列出您键入的源代码。语法如下:`/list [<name or id> &#124; -all &#124; -start]` |
......@@ -176,7 +176,7 @@ jshell <options> <load files>
![](img/7e1da0de-02ab-4b9c-8a69-8452b355def4.png)
作为一个例子,让我们浏览一下 truncation 设置,该设置要求在每个输出行上显示多少个字符。使用`/set truncation`命令,如下面的屏幕截图所示,显示当前的截断设置:
作为一个例子,让我们浏览一下`truncation`设置,该设置要求在每个输出行上显示多少个字符。使用`/set truncation`命令,如下面的屏幕截图所示,显示当前的截断设置:
![](img/d6c42080-2734-48f5-a805-d520602e9154.png)
......
......@@ -88,7 +88,7 @@ JVM 可以使用几种垃圾收集算法或类型。在本节中,我们将介
# 标记和扫描
Java 的初始垃圾收集算法 mark and sweep 使用了一个简单的两步过程:
Java 的初始垃圾收集算法标记清除使用了一个简单的两步过程:
1. 第一步,标记,是遍历所有具有可访问引用的对象,将这些对象标记为活动对象
......@@ -187,7 +187,7 @@ G1 垃圾收集算法还根据要收集的垃圾最多的区域来确定区域
| 您可以使用此命令在备注阶段之前强制年轻的集合。 | `-XX:+CMSScavengeBeforeRemark` |
| 如果使用的 Eden 低于阈值,则使用此选项可防止出现计划注释。 | `-XX:+CMSScheduleRemark\EdenSizeThreshold` |
| 设置您希望 CMS 尝试和安排备注暂停的 Eden 占用百分比。 | `-XX:CMSScheduleRemark\EdenPenetration=20` |
| 至少在新生代的入住率达到您想要安排备注的 1/4(在我们右边的示例中)之前,您就要在这里开始对 Eden top 进行采样。 | `-XX:CMSScheduleRemark\SamplingRatio=4` |
| 至少在新生代的入住率达到您想要安排备注的 1/4(在我们右边的示例中)之前,您就要在这里开始对 Eden 顶部进行采样。 | `-XX:CMSScheduleRemark\SamplingRatio=4` |
| 备注后可选择`variant=1``variant=2`验证。 | `-XX:CMSRemarkVerifyVariant=1` |
| 选择使用并行算法进行年轻空间的收集。 | `-XX:+UseParNewGC` |
| 允许对并发阶段使用多个线程。 | `-XX:+CMSConcurrentMTEnabled` |
......@@ -283,7 +283,7 @@ public class GCVerificationTest {
除了使用`System.gc()`方法调用垃圾收集器之外,还有一种替代方法。在我们的例子中,我们可以使用`myRuntime.gc()`,我们早期的单例例子。
# finalize()方法
# `finalize()`方法
你可以把 Java 的垃圾收集器想象成死亡贩子。当它从记忆中删除某些东西时,它就消失了。这个所谓的死亡贩子并非没有同情心,因为它为每个方法提供了他们最后的遗言。对象通过`finalize()`方法给出他们的最后一句话。如果一个对象有一个`finalize()`方法,垃圾收集器会在移除该对象和释放相关内存之前调用它。该方法不带参数,返回类型为`void`
......@@ -640,7 +640,7 @@ Java9 日志框架支持三种类型的输出:
# gc 标签
我们可以使用带有`-Xlog`选项的`gc`标记来通知 JVM 在 info 级别只记录`gc`标记的项。您还记得,这类似于使用`-XX:+PrintGC`。使用这两个选项,JVM 将为每个垃圾收集操作记录一行。
我们可以使用带有`-Xlog`选项的`gc`标记来通知 JVM 在`info`级别只记录`gc`标记的项。您还记得,这类似于使用`-XX:+PrintGC`。使用这两个选项,JVM 将为每个垃圾收集操作记录一行。
值得注意的是,`gc`标签并非单独使用,而是建议与其他标签一起使用。
......@@ -658,7 +658,7 @@ log_<level>(Tag1[,...])(fmtstr, ...)
log_debug(gc, classloading)("Number of objects loaded: %d.", object_count)
```
下面的示例 skeleton`log`宏显示了如何使用新的 Java 日志框架来创建脚本,以提高日志记录的逼真度:
下面的示例框架`log`宏显示了如何使用新的 Java 日志框架来创建脚本,以提高日志记录的逼真度:
```java
LogHandle(gc, rt, classunloading) log;
......@@ -705,18 +705,18 @@ if (log.is_trace()) {
正如本章前面提到的,G1 垃圾收集器自 Java9 以来一直是默认的垃圾收集器。G1 垃圾收集器的效率之一是它使用并发垃圾收集而不是完全收集。有时会实现完全垃圾收集,通常是并发垃圾收集速度不够快。注意,在 Java9 之前,并行收集器是默认的垃圾收集器,是一个并行的完全垃圾收集器。
对于 Java10,g1full 垃圾回收器被转换为 parallel,以减轻对使用 full 垃圾回收的开发人员的任何负面影响。将用于 G1 完全垃圾回收的 mark-week 压缩算法并行化。
对于 Java10,G1Full 垃圾回收器被转换为并行,以减轻对使用完全垃圾回收的开发人员的任何负面影响。将用于 G1 完全垃圾回收的 mark-week 压缩算法并行化。
# Epsilon–任意低开销 GC
Java 的最新版本 version11 附带了一个负责内存分配的被动 GC。这个 GC 的被动性质(称为 epsilongc)表明它不执行垃圾收集;相反,它继续分配内存,直到堆上没有剩余空间为止。这时,JVM 关闭。
Java 的最新版本 11 附带了一个负责内存分配的被动 GC。这个 GC 的被动性质(称为 EpsilonGC)表明它不执行垃圾收集;相反,它继续分配内存,直到堆上没有剩余空间为止。这时,JVM 关闭。
为了启用 Epsilon GC,我们使用以下任一方法:
* `-XX:+UseEpsilonGC`
* `-XX:+UseNoGC`
epsilongc 的使用主要出现在测试中,由于缺乏垃圾收集,它的开销很低,提高了测试效率
EpsilonGC 的使用主要出现在测试中,由于缺乏垃圾收集,它的开销很低,提高了测试效率
# 长期存在的问题
......@@ -750,7 +750,7 @@ public class GarbageCollectionExperimentOne {
}
```
如在代码注释中所示,一旦 string object 引用变量设置为`null`,在本例中使用`junk = null;`语句,对象就可以进行垃圾收集。
如在代码注释中所示,一旦字符串对象引用变量设置为`null`,在本例中使用`junk = null;`语句,对象就可以进行垃圾收集。
在我们的下一个示例中,我们将通过将对象的引用变量设置为指向另一个对象来放弃该对象。正如您在以下代码中看到的,这导致第一个对象可用于垃圾收集:
......
......@@ -37,7 +37,7 @@ IDE 软件包就足够了。来自 JetBrains 的 IntelliJ IDEA 用于与本章
Oracle 的文档表明,最理想的 JMH 用例是使用依赖于应用程序 JAR 文件的 Maven 项目。他们进一步建议微标记通过命令行进行,而不是从 IDE 中进行,因为这可能会影响结果。
Maven,也称为 apachemaven,是一个项目管理和理解工具,我们可以使用它来管理我们的应用程序项目构建、报告和文档。
Maven,也称为 ApacheMaven,是一个项目管理和理解工具,我们可以使用它来管理我们的应用程序项目构建、报告和文档。
为了使用 JMH,我们将使用字节码处理器(注释)来生成基准代码。
......@@ -51,7 +51,7 @@ Maven,也称为 apachemaven,是一个项目管理和理解工具,我们可
# 动手实验
现在我们已经安装了 eclipseoxygen,您可以运行一个快速测试来确定 JMH 是否在您的开发计算机上工作。首先创建一个新的 Maven 项目,如以下屏幕截图所示:
现在我们已经安装了 EclipseOxygen,您可以运行一个快速测试来确定 JMH 是否在您的开发计算机上工作。首先创建一个新的 Maven 项目,如以下屏幕截图所示:
![](img/4889a0b4-6ec1-4e9a-b8e8-d7b61065eaf9.png)
......@@ -97,7 +97,7 @@ JMH 测试结果
# Maven 微基准
开始使用 JMH 的一种方法是使用 jmhmaven 原型。第一步是创建一个新的 JMH 项目。在我们系统的命令提示符下,我们将输入`mvn`命令,然后输入一组长参数,以创建一个新的 Java 项目和必要的 Maven`pom.xml`文件:
开始使用 JMH 的一种方法是使用 JMHMaven 原型。第一步是创建一个新的 JMH 项目。在我们系统的命令提示符下,我们将输入`mvn`命令,然后输入一组长参数,以创建一个新的 Java 项目和必要的 Maven`pom.xml`文件:
```java
mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=org.openjdk.jmh -DarchetypeArtifactId=jmh-java-benchmark-archetype -DgroupId=com.packt -DartifactId=chapter8-benchmark -Dversion=1.0
......@@ -334,7 +334,7 @@ if (value != null) {
. . .
```
在我们前面的示例中,由于变量值永远不会等于 null,因此永远不会到达标识为死代码的行。在条件语句`if`计算变量之前,它被设置为`10`
在我们前面的示例中,由于变量值永远不会等于`null`,因此永远不会到达标识为死代码的行。在条件语句`if`计算变量之前,它被设置为`10`
问题是,为了消除死代码,有时可以删除基准测试代码。
......@@ -355,7 +355,7 @@ int newValue = 3190;
对于这个陷阱,有一个建议的策略:
* 使用 jmhAPI 支持来确保您的基准测试代码不会被消除
* 使用 JMH API 支持来确保您的基准测试代码不会被消除
# 运行间差异
......
......@@ -8,7 +8,7 @@
* 引入流程
* 使用`ProcessHandle`接口
* 查看示例 process controller 应用程序
* 查看示例进程控制器应用程序
# 技术要求
......@@ -34,7 +34,7 @@ IDE 软件包就足够了。来自 JetBrains 的 IntelliJ IDEA 用于与本章
程序可以准备在收到此类请求时停止。例如,Java 应用程序可以添加一个调用`Runtime.getRuntime().addShutdownHook(Thread t)`方法的`Thread`对象。传递的线程应该在进程被要求停止时启动,这样线程就可以执行程序退出前必须执行的所有任务。不幸的是,不能保证线程会真正启动,这取决于实际的实现。
# 使用 ProcessHandle 接口
# 使用`ProcessHandle`接口
Java9 中引入了两个支持处理操作系统进程的新接口-`ProcessHandle``ProcessHandle.Info`
......@@ -159,7 +159,7 @@ public class ChildLister {
列出子进程与列出子进程非常相似,但是如果我们调用`processHandle.descendants()`方法,那么`Stream`将包含所有子进程以及这些进程的子进程,依此类推。
以下程序以命令行参数启动命令提示,以便它们也生成另一个终止的【T0”
以下程序以命令行参数启动命令提示,以便它们也生成另一个终止的`cmd.exe`
```java
import java.io.IOException;
......@@ -286,7 +286,7 @@ public class TerminateAProcessAfterWaiting {
示例代码将睡眠时间设置为 10 秒。这是一个更明显的时间段。运行两次代码并删除破坏进程的行会导致打印速度慢得多。实际上,测量和打印的运行时间也会显示终止进程会产生影响。
# 查看示例 process controller 应用程序
# 查看示例进程控制器应用程序
最后一节提供了一个示例过程控制应用程序来演示本章的内容。应用程序的功能非常简单。它从一系列配置文件参数中读取如何启动某些进程,然后,如果其中任何进程停止,它将尝试重新启动进程。
......@@ -390,7 +390,7 @@ public class ParamsAndHandle {
}
```
由于该类与使用它的`ControlDaemon`类紧密相连,因此没有与该字段相关联的 mutator 或 accessor。我们把这两个类看作是在同一个封装边界内的东西。`toHandle () `方法就在那里,所以我们可以将它用作方法句柄,我们将在第 10 章、“细粒度栈跟踪”中看到。
由于该类与使用它的`ControlDaemon`类紧密相连,因此没有与该字段相关联的更改器或访问器。我们把这两个类看作是在同一个封装边界内的东西。`toHandle () `方法就在那里,所以我们可以将它用作方法句柄,我们将在第 10 章、“细粒度栈跟踪”中看到。
# 控制守护进程
......
......@@ -125,7 +125,7 @@ public class CheckEligibility {
![](img/8da943bd-0406-4257-8bcb-2707259cb2a4.png)
StackFrame 在库中找到的类
`StackFrame`在库中找到的类
# 示例–为呼叫者获取记录器
......@@ -154,7 +154,7 @@ public class Labrador {
接下来,我们来看看`StackWalker`的细节。
# 与 StackWalker 合作
# 与`StackWalker`合作
在本节中,您将熟悉如何使用`StackWalker`。本节将探讨以下主题:
......@@ -163,7 +163,7 @@ public class Labrador {
* 访问类
* 步行法
# 正在获取 StackWalker 的实例
# 正在获取`StackWalker`的实例
要遍历栈元素,我们需要一个`StackWalker`的实例。为此,我们调用`getInstance()`方法。如图所示,此方法有四个重载版本:
......@@ -172,7 +172,7 @@ public class Labrador {
* `static StackWalker getInstance(Set<StackWalker.Option> options)`
* `static StackWalker getInstance(Set<StackWalker.Option> options, int estimateDepth)`
第一个版本不接受任何参数,并返回一个`StackWalker`实例,让我们遍历正常的栈帧。这通常是我们感兴趣的。该方法的其他版本接受一个或多个`StackWalker.Option`值。顾名思义,enum`StackWalker.Option``StackWalker`类中,有三个值:
第一个版本不接受任何参数,并返回一个`StackWalker`实例,让我们遍历正常的栈帧。这通常是我们感兴趣的。该方法的其他版本接受一个或多个`StackWalker`类中的`StackWalker.Option`枚举,有三个值:
* `RETAIN_CLASS_REFERENCE`
* `SHOW_REFLECT_FRAMES`
......@@ -180,19 +180,19 @@ public class Labrador {
# 枚举选项
`RETAIN_CLASS_REFERENCE``SHOW_REFLECT_FRAMES``SHOW_HIDDEN_FRAMES`enum 选项具有自描述性名称,下面将对其进行说明。
`RETAIN_CLASS_REFERENCE``SHOW_REFLECT_FRAMES``SHOW_HIDDEN_FRAMES`枚举选项具有自描述性名称,下面将对其进行说明。
# 保留等级参考
# `RETAIN_CLASS_REFERENCE`
如果我们指定第一个选项 enum constant`RETAIN_CLASS_REFERENCE`作为`getInstance()`方法的参数,那么返回的实例将授予我们访问各个栈在遍历期间引用的类的权限。
如果我们指定第一个选项的枚举常量`RETAIN_CLASS_REFERENCE`作为`getInstance()`方法的参数,那么返回的实例将授予我们访问各个栈在遍历期间引用的类的权限。
# 显示\u 反射\u 帧
# `SHOW_REFLECT_FRAMES`
`SHOW_REFLECT_FRAMES`enum 常量将生成一个 walker,其中包含来自某个反射调用的帧。
`SHOW_REFLECT_FRAMES`枚举常量将生成一个遍历器,其中包含来自某个反射调用的帧。
# 显示隐藏的帧
# `SHOW_HIDDEN_FRAMES`
最后,enum constant 选项`SHOW_HIDDEN_FRAMES`将包括所有隐藏帧,其中包含反射调用以及为 Lambda 函数调用生成的调用帧。
最后,枚举常量选项`SHOW_HIDDEN_FRAMES`将包括所有隐藏帧,其中包含反射调用以及为 Lambda 函数调用生成的调用帧。
下面是反射和隐藏框架的简单演示:
......@@ -348,7 +348,7 @@ stackwalker/packt.Main.main(Main.java:8)
在大多数情况下,它的效率较低,因为它强制`StackWalker`实例获取栈跟踪的所有元素,这样`forEach()`方法就可以遍历每个元素到最后。如果我们知道我们不会遍历栈跟踪到最后,我们应该使用`walk()`方法,即以惰性的方式访问栈,从而为性能优化留下更多的空间。
`StackWalker`类有`walk()`方法,这是使其成为 walker 的定义方法。该方法接受由`StackWalker`调用的函数。`walk()`方法的返回值将是函数返回的对象。函数的参数是传递栈帧的`Stream<StackFrame>`。第一帧是包含`walk()`方法调用的帧,下一帧是调用包含`walk()`方法调用的帧,依此类推。
`StackWalker`类有`walk()`方法,这是使其成为遍历器的定义方法。该方法接受由`StackWalker`调用的函数。`walk()`方法的返回值将是函数返回的对象。函数的参数是传递栈帧的`Stream<StackFrame>`。第一帧是包含`walk()`方法调用的帧,下一帧是调用包含`walk()`方法调用的帧,依此类推。
该函数可用于根据来自流的`StackFrame`对象计算一些值,并决定调用方是否有资格调用我们的代码。
......@@ -371,7 +371,7 @@ public static void itIsNotCallBack() {
}
```
我们所做的只是直接从 walker 调用返回流,然后遍历流,然后执行相同的计算。我们的结果是`IllegalStateException`例外,而不是资格检查。
我们所做的只是直接从遍历器调用返回流,然后遍历流,然后执行相同的计算。我们的结果是`IllegalStateException`例外,而不是资格检查。
原因是`StackWalker`的实现高度优化。它不会复制整个栈来为流提供源信息。它是从实际的,活生生的栈中工作的。为此,必须确保在使用流时不修改栈。这与迭代集合时更改集合可能得到的`ConcurrentModificationException`异常非常相似。如果我们在调用栈中向上传递流,然后想要从中获取`StackFrame`,那么流将尝试从早已消失的栈帧中获取信息,因为我们从它所属的方法返回。这样,`StackWalker`就不会生成整个栈的快照,而是从实际栈开始工作,并且必须确保所需的栈部分不会更改。我们可以从函数中调用方法,这样我们可以在调用链中更深入地挖掘,但是在流被使用时,我们不能得到更高的值。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册