

# 自定义 Lambda 函数的 Java 运行时启动行为
<a name="java-customization"></a>

本页将介绍特定于 AWS Lambda 中 Java 函数的设置。您可以使用这些设置来自定义 Java 运行时系统启动行为。这样可以减少总体函数延迟并提高总体函数性能，而无需修改任何代码。

**Topics**
+ [

## 了解 `JAVA_TOOL_OPTIONS` 环境变量
](#java-tool-options)
+ [

## Log4Shell 的 Log4j 补丁
](#log4shell-patch)
+ [

## 提前编译（AOT）和 CDS 缓存
](#aot-cds-caches)

## 了解 `JAVA_TOOL_OPTIONS` 环境变量
<a name="java-tool-options"></a>

在 Java 中，Lambda 支持 `JAVA_TOOL_OPTIONS` 环境变量以在 Lambda 中设置其他命令行变量。您可以通过多种方式使用此环境变量，例如自定义分层编译设置。下一个示例演示了如何针对此使用案例使用 `JAVA_TOOL_OPTIONS` 环境变量。

### 示例：自定义分层编译设置
<a name="tiered-compilation"></a>

分层编译是 Java 虚拟机（JVM）的一项功能。您可以使用特定的分层编译设置来充分利用 JVM 的即时（JIT）编译器。通常，C1 编译器经过优化，可缩短启动时间。C2 编译器经过优化以获得最佳整体性能，但它也会占用更多内存，并且需要更长的时间才能实现。分层编译有 5 个不同级别。在级别 0 上，JVM 解释 Java 字节代码。在级别 4 上，JVM 使用 C2 编译器来分析在应用程序启动期间收集的分析数据。随着时间的推移，它会监控代码使用情况以确定最佳优化。

自定义分层编译级别有助于您优化 Java 函数的性能。对于执行速度较快的小型函数，将分层编译级别设置为 1 级可以通过让 JVM 使用 C1 编译器来帮助提升冷启动性能。该设置可以快速生成优化原生代码，但它不生成任何分析数据，也从不使用 C2 编译器。对于计算密集型的大型函数，将分层编译设置为 4 级可最大限度地提高整体性能，但会带来额外的内存消耗以及每次在 Lambda 执行环境预置后首次调用时的额外优化工作。

对于 Java 11 运行时及更低版本，Lambda 使用默认的 JVM 分层编译设置。对于 Java 17 和 Java 21，Lambda 将 JVM 配置为默认在级别 1 停止分层编译。从 Java 25 开始，Lambda 仍会默认在级别 1 停止分层编译，除非使用 SnapStart 或预置并发，在这种情况下，将使用默认的 JVM 设置。这提高了 SnapStart 和预置并发的性能，同时又不会产生冷启动的负面影响，因为在这些情况下，分层编译是在调用路径之外进行的。为了充分发挥这一优势，您可以在函数初始化过程中使用引导 - 执行代码路径，以便在拍摄 SnapStart 快照之前或在预置并发执行环境被预先配置时触发 JIT。有关更多信息，请参阅博客文章[利用 SnapStart 结合先进的引导策略来优化 AWS Lambda 的冷启动性能](https://aws.amazon.com/blogs/compute/optimizing-cold-start-performance-of-aws-lambda-using-advanced-priming-strategies-with-snapstart/)。

**自定义分层编译设置（控制台）**

1. 在 Lambda 控制台中打开[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择要为其自定义分层编译的 Java 函数。

1. 选择**配置**选项卡，然后从左侧菜单中选择**环境变量**。

1. 选择**编辑**。

1. 选择**添加环境变量**。

1.  对于键，输入 `JAVA_TOOL_OPTIONS`。对于值，输入 `-XX:+TieredCompilation -XX:TieredStopAtLevel=1`。  
![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/java-tool-options-tiered-compilation.png)

1. 选择**保存**。

**注意**  
您也可以使用 Lambda SnapStart 来缓解冷启动问题。SnapStart 使用执行环境的缓存快照来显著提高启动性能。有关 SnapStart 的功能、限制和支持的区域的更多信息，请参阅 [使用 Lambda SnapStart 提高启动性能](snapstart.md)。

### 示例：使用 JAVA\$1TOOL\$1OPIONS 自定义 GC 行为
<a name="gc-behavior"></a>

Java 11 运行时系统使用[串行](https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-45794DA6-AB96-4856-A96D-FDE5F7DEE498)垃圾收集器（GC）实现垃圾回收。默认情况下，Java 17 运行时系统也使用串行 GC。不过，在 Java 17 中，您也可以使用 `JAVA_TOOL_OPTIONS` 环境变量来更改默认 GC。您可以在 Parallel GC 和 [Shenandoah GC](https://wiki.openjdk.org/display/shenandoah/Main) 之间进行选择。

例如，如果工作负载会使用更多内存和多个 CPU，则考虑使用 Parallel GC 来获得更好的性能。为此，您可以将以下内容附加到 `JAVA_TOOL_OPTIONS` 环境变量的值中：

```
-XX:+UseParallelGC
```

如果您的工作负载中包含大量临时对象，则通过启用 Java 25 中引入的 Shenandoah 垃圾回收器代际模型，您可能会降低内存消耗从而获得益处。为此，可以将以下内容附加到 `JAVA_TOOL_OPTIONS` 环境变量的值中：

```
-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational
```

## Log4Shell 的 Log4j 补丁
<a name="log4shell-patch"></a>

适用于 Java 8、11、17 和 21 的 Lambda 运行时包括 Log4j（一款广受欢迎的 Java 日志记录框架）中的 Log4Shell 漏洞（CVE-2021-44228）的修复补丁。此修复补丁会产生冷启动性能开销。如果您使用的是 Log4j 的补丁版本（版本 2.17.0 或更高版本），则可以禁用此补丁以提高冷启动性能。要禁止此补丁，请将环境变量 `AWS_LAMBDA_DISABLE_CVE_2021_44228_PROTECTION` 设置为 `true`。

从 Java 25 版本开始，Lambda 运行时不再包含 Log4Shell 补丁。您必须确认您使用的是 Log4j 版本 2.17.0 或更高版本。

## 提前编译（AOT）和 CDS 缓存
<a name="aot-cds-caches"></a>

从 Java 25 版本开始，Lambda 运行时为 Java 运行时接口客户端（RIC）配备了提前编译（AOT）缓存。RIC 是一个会主动从 Lambda 运行时 API 轮询事件的运行时组件。这可以提高冷启动性能。

AOT 缓存特定于 JVM 版本。当 Lambda 更新托管运行时时，它还会更新 RIC 的 AOT 缓存。但是，如果您部署自己的 AOT 缓存，则在运行时更新后，这些缓存可能会失效，或者导致出现意外情况。因此，我们强烈建议在使用托管运行时时不要使用 AOT 缓存。要使用 AOT 缓存，您需要使用容器映像来部署您的函数。

AOT 缓存不能与类数据共享（CDS）缓存一起使用。如果您在 Lambda 函数中部署了 CDS 缓存，则 Lambda 会禁用 AOT 缓存。