浏览器运行 Node.js! WebContainer 1.0 发布!

2023-09-09 1795阅读

2021 年,StackBlitz 发布了 WebContainers,这是一个基于 WebAssembly 的新操作系统,使 Node.js 能够完全在浏览器中运行。2023 年 2 月 14 日,StackBlitz 公开发布了 WebContainer API,邀请整个 JavaScript 和 Node.js 社区在 WebContainer 之上构建应用程序!截至本文发表,StackBlitz 已经基于 WebContainer 构建了 StackBlitz Editor、Codeflow IDE 和 Web Publisher 等公共产品。WebContainers 提供的 API 允许无头访问,使开发人员能够灵活地在该技术的基础上构建自己的应用程序。同时,WebContainers的许多功能已经开源,并为企业用例提供支持和许可。Node.js 命令可以直接传递到 WebContainers,以便在页面加载或由应用程序中的用户操作触发时执行。由 Rich Harris 领导的 Svelte 已经开始使用 WebContainers。

大家好,很高兴再次见面。 我是“前端高级进阶”。 我将带领大家关注前端前沿,深入研究前端底层技术。 我们将共同进步。 也欢迎您关注、点赞、收藏、转发。 !

浏览器工作原理简单说明_浏览原理器工作是什么意思_浏览器工作原理是怎样的

先进的前端进步

前言

2021 年,StackBlitz 发布了 WebContainers,这是一个基于 WebAssembly 的新操作系统,使 Node.js 能够完全在浏览器中运行。 在过去的两年里,每个月都有数百万开发者使用WebContainers,比如典型的应用程序StackBlitz编辑器。

2023 年 2 月 14 日,StackBlitz 公开发布了 WebContainer API,邀请整个 JavaScript 和 Node.js 社区在 WebContainer 之上构建应用程序! 截至本文发表,StackBlitz 已经基于 WebContainer 构建了 StackBlitz Editor、Codeflow IDE 和 Web Publisher 等公共产品。

1.什么是Web容器?

WebContainers 是一个基于 WebAssembly 的微型操作系统,允许在浏览器选项卡中本地启动 Node.js 服务器。 将其视为“Electron polyfill”,当页面在浏览器中加载时无缝交付。

浏览原理器工作是什么意思_浏览器工作原理简单说明_浏览器工作原理是怎样的

WebContainers 提供的 API 允许无头访问,使开发人员能够灵活地在该技术的基础上构建自己的应用程序。 同时,WebContainers的许多功能已经开源,并为企业用例提供支持和许可。 WebContainers的主要功能包括:

浏览器工作原理是怎样的_浏览器工作原理简单说明_浏览原理器工作是什么意思

2. WebContainers API 主要功能 2.1 浏览器内文件系统

WebContainers 使用存储在内存中的临时虚拟文件系统启动,允许开发人员以编程方式加载/加载文件和目录,并对它们执行标准文件系统操作。

const file = await webcontainerInstance.fs.readFile('/package.json', 'utf-8');
//   readFile文件
const files = await webcontainerInstance.fs.readdir('/src');
// readdir读取目录
await webcontainerInstance.fs.rm('/src', { recursive: true });
// 删除目录
await webcontainerInstance.fs.writeFile('/src/main.js', 'console.log("Hello from WebContainers!")');
// 写文件
await webcontainerInstance.fs.mkdir('src');
// mkdir

2.2 开发服务器

HTTP 服务器可以在 WebContainer 中按需启动,并接收预览 URL,该预览 URL 可以与用户共享或使用 iframe 直接在应用程序中显示。 虚拟化 TCP 网络堆栈映射到浏览器的 ServiceWorker API 并完全在本地运行,因此即使用户失去 Internet 连接,服务器也将继续工作。

async function startDevServer() {
  // 执行 `npm run start` 启动Express服务器
  await webcontainerInstance.spawn('npm', ['run', 'start']);
  // 等待 `server-ready` 事件
  webcontainerInstance.on('server-ready', (port, url) => {
    iframeEl.src = url;
  });
}

浏览器运行 Node.js!  WebContainer 1.0 发布!

在浏览器开发工具中,下一步运行startDevServer()后,您将可以看到正在运行的开发服务器:

浏览器工作原理简单说明_浏览原理器工作是什么意思_浏览器工作原理是怎样的

注意:WebContainer 公开服务器就绪事件,该事件在服务器准备好接受请求时发出。 您可以使用 webcontainerInstance.on 来监听事件。

2.3 Node.js命令行

Node.js 命令可以直接传递到 WebContainers,以便在页面加载或由应用程序中的用户操作触发时执行。 您可以 npm 安装软件包、启动新的节点服务器或构建应用程序,就像在本地开发环境中一样。

webcontainerInstance.spawn('npm', ['install']);
webcontainerInstance.spawn('ls', ['src', '-l']);
// 安装依赖
async function installDependencies() {
  const installProcess = await webcontainerInstance.spawn('npm', ['install']);
  return installProcess.exit;
}
// 函数调用
window.addEventListener('load', async () => {
  textareaEl.value = files['index.js'].file.contents;
  webcontainerInstance = await WebContainer.boot();
  await webcontainerInstance.mount(files);
  const exitCode = await installDependencies();
  // 安装依赖
  if (exitCode !== 0) {
    throw new Error('Installation failed');
  };
});

浏览器工作原理简单说明_浏览原理器工作是什么意思_浏览器工作原理是怎样的

总之,WebContainer API 为 Web 应用程序提供了新级别的灵活性、可扩展性和性能!

3. 使用WebContainer API 构建什么?

stackblitz 与社区成员密切合作,根据反馈、需求和问题开发了 WebContainer。 目前基于WebContainer的用例越来越多,比如以下经典用例:

3.1 交互式编码教程

由 Rich Harris 领导的 Svelte 已经开始使用 WebContainers。 他们构建了令人印象深刻的交互式教程,教您如何逐步使用 SvelteKit。 这是获得框架实践经验并了解其工作原理的好方法,同时获得好评如潮!

浏览原理器工作是什么意思_浏览器工作原理简单说明_浏览器工作原理是怎样的

Svelte 是一种构建用户界面的全新方式。 React 和 Vue 等传统框架需要在浏览器中进行大量工作,但 Svelte 在构建应用程序的编译阶段处理这些工作。

将此与使用虚拟 DOM diff 进行对比。 Svelte 编写的代码可以在应用程序状态发生变化时精确地更新 DOM。

3.2 生产级 Web IDE

StackBlitz 使用 Webcontainers 构建了 Codeflow IDE,Webcontainers 是桌面 Visual Studio Code IDE 的全功能版本,支持 git 命令、桌面扩展和带终端的 Node.js 开发服务器。

浏览器运行 Node.js!  WebContainer 1.0 发布!

浏览器工作原理是怎样的_浏览器工作原理简单说明_浏览原理器工作是什么意思

3.3 人工智能应用

WebContainer API 还解锁了开发人员可以创建的一类新的 AI 应用程序。 想象一下使用 OpenAI 集成来生成完全在浏览器中运行的实时应用程序!

浏览器工作原理简单说明_浏览原理器工作是什么意思_浏览器工作原理是怎样的

3.4 无代码/低代码环境

WebContainers 支持以前不可能的新的低代码或无代码解决方案。 StackBlitz 的用户友好型文档编辑工具 Web Publisher 等工具确实使网络更加开放并打破了进入壁垒。

浏览器工作原理简单说明_浏览器工作原理是怎样的_浏览原理器工作是什么意思

4. WebContainer的Hello-world示例

应用配置环境:

export const projectFiles = {
  myProject: {
    directory: {
      'package.json': {
        file: {
          contents: '...',
        }
      },
      'index.js': {
        file: {
          contents: '...',
        }
      },
    }
  }
};

你好世界.ts 程序:

import { WebContainer, FileSystemTree } from '@webcontainer/api';
import { projectFiles } from './project-files.ts';
async function main() {
  // 首先我们启动一个 WebContainer
  const webcontainer = await WebContainer.boot();
   // 启动容器后,我们复制所有项目文件
   // 进入容器的文件系统
  await webcontainer.mount(projectFiles);
   // 安装文件后,通过生成 `npm install` 来安装依赖
  const install = await webcontainer.spawn('npm', ['i']);
  await install.exit;
  // 一旦安装了所有依赖项,我们就可以生成 `npm`
  // 从项目的 `package.json` 运行 `dev` 脚本
  await webcontainer.spawn('npm', ['run', 'dev']);
}

5.本文总结

本文主要介绍如何在浏览器中运行Node.js。 还介绍了WebContainer 1.0,讨论了什么是WebContainer、WebContainers API的主要功能、使用WebContainer API的应用场景等!

WebContainer非常适合交互式编码体验,可用于生产级IDE、编程教程、下一代文档等场景。 虽然看起来功能非常有限,但它是从0到1的突破,它正在尝试在浏览器端运行一个微型操作系统。 相信在不久的将来,不仅是nodejs,还会有其他语言,比如python、Java等。

文末的参考资料提供了大量可供学习的优秀文档。 如果您有兴趣,可以自行阅读。 如果您有任何疑问,请在评论区留言。

参考

#安装依赖项

(启动 ImportNew 来提高您的 Java 技能)

在阿里云技术面谈结束时,被问到这样一个问题:假设一个平台每天有100万个登录请求,服务节点有8G内存,JVM参数如何设置?

下面以面试题的形式为大家整理一下,做到一箭双雕:既供大家实际参考,也供大家面试参考。

大家需要学习的,除了JVM的配置方案之外,就是它分析问题的方式和思考问题的视角。 这些想法和观点可以帮助大家走得越来越远。 接下来我们就进入正题吧。

每天100万个登录请求,8G内存如何设置JVM参数,大致可以分为以下8步。

第一步,新系统上线时如何规划容量?

1. 例程总结

任何新的业务系统上线之前,都需要对服务器配置和JVM内存参数进行预估。 这种容量和资源规划不仅仅是由系统架构师任意估计的。 需要根据系统所在的业务场景进行估算,才能推演出一个系统。 运行模型来评估JVM性能、GC频率等指标。 以下是我根据大牛的经验和自己的实践总结出来的建模步骤:

2.练习套路:以登录系统为例

有的同学看到这些步骤还是一愣,说的好像都是同一个东西。 实际项目中我还是不知道怎么做。 光说不练假动作,以登录系统为例来模拟推演过程:

因此可以粗略推断,一个每天100万请求的登录系统,按照4C8G 3实例集群配置,分配4G堆内存和2G新一代JVM,可以保证系统正常负载。

基本上是对一个新系统的资源进行评估,所以每个实例需要多少容量和配置来构建一个新系统,集群中配置多少个实例等等,这些都不是拍头拍胸就可以确定的。

第二步:如何选择垃圾收集器

吞吐量还是响应时间?

首先介绍两个概念——吞吐量和低延迟。

吞吐量 = CPU在用户应用程序运行的时间 / (CPU在用户应用程序运行的时间 + CPU垃圾回收的时间)
响应时间 = 平均每次的GC的耗时

通常,吞吐量优先级或响应优先级是 JVM 中的一个两难选择。

随着堆内存的增加,一次可以处理的GC数量增加,吞吐量增加; 但GC时间会变长,导致后面排队的线程等待时间变长; 反之,如果堆内存较小,则GC时间较短,排队时间会较长。 等待线程的等待时间变短,延迟减少,但同时请求的数量变少(不绝对一致)。

同时考虑两者是不可能的。 优先考虑吞吐量还是响应是一个需要权衡的问题。

垃圾收集器设计注意事项

CMS 和 G1

目前主流的垃圾收集器配置是在新生代使用ParNew,在老年代使用CMS组合,或者完全使用G1收集器。 从未来的趋势来看,G1是官方维护的、更受推崇的垃圾收集器。

上网记录会永久保存在终端吗_永久存储上网记录会消除吗_上网记录会永久存储吗

业务系统:对于延迟敏感、大内存的业务,以及需要高吞吐量的业务,推荐CMS,使用G1回收器。

CMS 垃圾收集器的工作原理

CMS主要针对老年代的收集器。 老一代的标记很清楚。 默认情况下,它会在Full GC算法之后执行排序算法来清理内存碎片。

永久存储上网记录会消除吗_上网记录会永久存储吗_上网记录会永久保存在终端吗

总之,对于延迟敏感的业务系统,推荐使用CMS。 对于需要高吞吐量的大内存服务,使用G1收集器。

第三步,如何规划各个分区的比例和大小。

总体思路是:

首先,JVM最重要、最核心的参数是评估内存和分配。 第一步是指定堆内存的大小,这必须在系统在线时完成。 -Xms是初始堆大小,-Xmx是最大堆大小,后台Java服务一般指定为系统内存的一半。 如果太大,就会占用服务器的系统资源。 如果太小,则无法发挥JVM的最佳性能。

其次,需要指定新生代-Xmn的大小。 这个参数非常关键且灵活。 虽然sun官方推荐的是3/8大小,但是要根据业务场景来确定。 它针对的是无状态或者轻状态服务(目前最常见的业务系统(如Web应用),一般新生代甚至可以给予3/4的堆内存大小;对于有状态服务(常见的系统如IM服务、网关接入层等),新生代分配可以按照默认比例1/3来设置,如果服务是有状态的,就意味着会有更多的本地缓存和会话状态信息驻留在内存中。这应该通过为老年代设置更大的空间来存储这些对象来完成。

最后设置-Xss栈内存大小,设置单个线程的栈大小。 默认值与JDK版本和系统有关,一般默认为512~1024kb。 如果一个后台服务有数百个常驻线程,那么堆栈内存也会占用数百M大小。

永久存储上网记录会消除吗_上网记录会永久保存在终端吗_上网记录会永久存储吗

对于8G内存,一般分配最大内存的一半就够了。 由于机器仍然占用一定的内存,所以一般分配4G内存给JVM。

引入性能压力测试环节,学生使用ParNew + CMS的组合回收器测试了登录界面1秒内60M的对象生成速度。

正常的JVM参数配置如下:

-Xms3072M -Xmx3072M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=8

由于动态对象年龄判断原理,该设置可能会导致频繁的Full GC。 为什么?

在压力测试过程中,Eden区会在短时间内(例如20秒后)就满了。 此时再次运行时,对象无法分配,会触发Minor GC。

假设本次GC后,S1负载100M,20秒后立即触发一次Minor GC。 S1区多余的100M存活对象+100M已经无法成功放入S2区,此时会触发JVM动态age机制,将一批100M左右的对象推送到老年代进行存储。 系统运行一段时间后,可能会在一小时内触发Full GC。

按照默认的8:1:1比例分配时,Survivor区只有1G的10%左右,也就是几十到100M。 如果每次Minor GC垃圾回收后有很多Survivor对象,并且Survivor对象的大小很快就会超过Survivor的50%,那么就会触发动态年龄判定规则,让部分对象进入老年代。

在一次GC过程中,有些Web请求可能没有处理完全,几十兆的对象进入Survivor的概率非常高,甚至会发生。

如何解决这个问题呢? 为了尽可能的保留新生代Eden区和Survivor区的对象,尽量让Survivor区有尽可能多的内存,达到200M左右。所以我们可以更新JVM参数设置:

-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M  -XX:SurvivorRatio=8  

阐明:

‐Xmn2048M ‐XX:SurvivorRatio=8

年轻代大小为2G,Eden与Survivor的比例为8:1:1,即1.6G:0.2G:0.2G。

达到200M,如果几十兆的对象存活下来,存活率可能不会超过50%。 这样可以防止每次垃圾回收后Survivor对象过早超过50%,从而减少由于对象的动态年龄判断原理导致对象频繁进入老年代的问题。

JVM动态年龄判断规则是什么?

进入老年代的对象的动态年龄判断规则(动态晋升年龄计算阈值):Minor GC时,当Survivor中年龄为1到N的对象大小超过Survivor的50%时,年龄大于等于N的对象会被放到老年代。

核心优化策略是尽可能保留Survivor中短期存活的对象,不进入老年代。 这样这些对象就会在Minor GC时被回收,不会进入老年代而引发full gc。

我们应该如何评估新一代内存并合理分配?

特别地,这里是JVM评估内存和分配的最重要、最核心的参数。

第一步是指定堆内存的大小。 系统上线时需要此操作。 -Xms 是初始堆大小,-Xmx 是最大堆大小。 在后台Java服务中,一般指定为系统内存的一半。 如果太大,就会占用服务器的系统。 如果资源太小,则无法发挥JVM的最佳性能。

上网记录会永久存储吗_上网记录会永久保存在终端吗_永久存储上网记录会消除吗

其次,需要指定新生代-Xmn的大小。 这个参数非常关键,并且具有很大的灵活性。 虽然Oracle官方推荐大小为3/8,但要根据业务场景来确定:

服务是有状态的,这意味着内存中会有更多的本地缓存和会话状态信息常驻,因此应该在老年代中设置更多的空间来存储这些对象。

第四步,栈内存的大小比较合适

xss栈内存大小,设置单个线程的栈大小。 默认值与JDK版本和系统有关。 默认值一般为512~1024 kb。 如果一个后台服务有数百个常驻线程,那么堆栈内存也会占用数百M大小。

步骤5:对象的年龄是多少才适合将其移动到老年代?

假设一次minor gc需要二十到三十秒,大多数对象一般会在几秒内变成垃圾。

如果对象这么长时间都没有被回收,比如2分钟都没有被回收,那么可以认为这些对象会存活比较长的时间,会被移到老年代而不是继续下去占据Survivor区空间。

因此,可以将默认的年龄15更改为更小的值,例如5。这意味着对象要经过5次Minor GC才能进入老年龄。 整个时间一两分钟(5*30s = 150s)。 与几秒钟相比,该物体已经存活了足够长的时间。

因此,可以适当调整JVM参数,如下:

‐Xms3072M ‐Xmx3072M ‐Xmn2048M ‐Xss1M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:SurvivorRatio=8 ‐XX:MaxTenuringThreshold=5 

步骤 6. 物体有多大? 直接移到老年代比较合适。

关于多大的对象直接进入老年代(参数-XX:PretenureSizeThreshold),一般可以用自己的系统看看是否有大对象产生,估计大对象的大小。 一般来说,设置为1M就足够了。 大于 1M 的大型物体很少见。 因此,可以适当调整JVM参数,如下:

‐Xms3072M ‐Xmx3072M ‐Xmn2048M ‐Xss1M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:SurvivorRatio=8 ‐XX:MaxTenuringThreshold=5 ‐XX:PretenureSizeThreshold=1M


步骤7.老一代垃圾收集器CMS的参数优化

JDK8默认的垃圾收集器是-XX:+UseParallelGC(年轻代)和-XX:+UseParallelOldGC(老年代)。 如果内存较大(4G以上,只是经验值),建议使用G1。

这是4G范围内的一个以“低时延”为核心的业务系统。 您可以使用以下组合:

ParNew+CMS(-XX:+UseParNewGC -XX:+UseConcMarkSweepGC)

新生代采用ParNew收集器,工作流程是经典的复制算法,分三个区域循环回收。 但采用多线程并行的方式来加速MinorGC。

老一代使用CMS。 然后优化老年代参数:比如清除标记后老年代会默认排序。 您还可以选择增加 GC 频率或增加 CMS 的 GC 持续时间。 以下是响应优先的参数调整:

XX:CMSInitiatingOccupancyFraction=70

设置CMS在内存使用率达到70%时启动GC(因为CMS会有浮动垃圾,所以GC一般会提前启动)。

XX:+UseCMSInitiatinpOccupancyOnly

和上面搭配使用,否则只生效一次:


-XX:+AlwaysPreTouch

强制操作系统实际分配内存给IVM,而不是在使用时分配。

综上所述,只要合理设置年轻代的参数,老年代CMS的参数设置基本可以使用默认值,如下所示:

‐Xms3072M ‐Xmx3072M ‐Xmn2048M ‐Xss1M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:SurvivorRatio=8  ‐XX:MaxTenuringThreshold=5 ‐XX:PretenureSizeThreshold=1M ‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC ‐XX:CMSInitiatingOccupancyFraction=70 ‐XX:+UseCMSInitiatingOccupancyOnly ‐XX:+AlwaysPreTouch

参数说明

‐Xms3072M ‐Xmx3072M 最小和最大堆设置为3G,最大和最小设置一致,防止内存抖动;

‐Xss1M线程栈1M;

‐Xmn2048M ‐XX:SurvivorRatio=8 年轻代大小为2G,Eden与Survivor的比例为8:1:1,即1.6G:0.2G:0.2G;

XX:MaxTenuringThreshold=5 年龄为5,进入老年代;

‐XX:PretenureSizeThreshold=1M 大于1M的大对象直接在老年代生成;

‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC 使用 ParNew+cms 垃圾收集器组合;

‐XX:CMSInitiatingOccupancyFraction=70 当老年代的对象达到该比例时,触发Full GC;

‐XX:+UseCMSInitiatinpOccupancy仅当老年代中的对象达到该比例时才触发FullGC;

‐XX:+AlwaysPreTouch 强制操作系统实际为 IVM 分配内存,而不是在使用时才分配。

步骤8.配置OOM时的内存转储文件和GC日志

增加了GC日志打印、OOM自动转储等额外配置内容,帮助排查问题。

-XX:+HeapDumpOnOutOfMemoryError

Out Of Memory,当JVM即将死掉时,Heap Dump被输出到指定文件。 不然开发中很多时候真的不知道如何重现错误。 路径只指向目录,JVM会保持文件名唯一,称为java_pid${pid}.hprof。

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOGDIR}/


因为如果指向特定的文件,而文件已存在,反而不能写入。


输出 4G 的 HeapDump,会导致 IO 性能问题,在普通硬盘上,会造成 20 秒以上的硬盘 IO 跑满,需要注意一下,但在容器环境下,这个也会影响同一宿主机上的其他容器。

GC 的日志的输出也很重要:


-Xloggc:/dev/xxx/gc.log -XX:+PrintGCDateStamps -XX:+PrintGCDetails

GC日志实际上对系统性能影响不大,日志记录对于排查GC问题非常重要。

常见的JVM参数模板

一般来说,大公司或者架构师团队都会为项目的业务系统定制一个比较通用的JVM参数模板,但是很多小企业和团队可能会忽略这方面的设计。 如果有一天你的老板突然要求你定制一个新系统的JVM参数,而你在网上搜索了大量的JVM调优文章或博客,你会发现都是零散的、不系统的JVM参数解释,而你将无法启动。 。 这时候就需要一个更通用的JVM参数模板。 它不能保证性能最好,但至少可以让JVM层稳定可控。

以下是为您提供的模板摘要:

基于4C8G系统的ParNew+CMS采集器模板(响应优先),新生代大小可根据业务灵活调整!

-Xms4g-Xmx4g-Xmn2g-Xss1m-XX:SurvivorRatio=8-XX:MaxTenuringThreshold=10-XX:+UseConcMarkSweepGC-XX:CMSInitiatingOccupancyFraction=70-XX:+UseCMSInitiatingOccupancyOnly-XX:+AlwaysPreTouch-XX:+HeapDumpOnOutOfMemoryError-verbose:gc-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintGCTimeStamps-Xloggc:gc.log


如果优先考虑GC的吞吐量,推荐使用G1,基于8C16G系统的G1收集器模板:

永久存储上网记录会消除吗_上网记录会永久保存在终端吗_上网记录会永久存储吗

G1收集器本身已经有一套预测和调整机制,所以我们的第一选择就是信任它。

即调整-XX:MaxGCPauseMillis=N参数,这也符合G1的目的——让GC调优尽可能简单。

同时,不要自己显式设置新生代的大小(使用-Xmn或-XX:NewRatio参数),

如果人为干预新生代的大小,目标时间的参数就会失效。

-Xms8g-Xmx8g-Xss1m-XX:+UseG1GC-XX:MaxGCPauseMillis=150-XX:InitiatingHeapOccupancyPercent=40-XX:+HeapDumpOnOutOfMemoryError-verbose:gc-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintGCTimeStamps-Xloggc:gc.log

上网记录会永久保存在终端吗_永久存储上网记录会消除吗_上网记录会永久存储吗

对于-XX:MaxGCPauseMillis,该参数设置有一个明显的倾向:较低↓:延迟较低,但Minor GC频繁,Mix GC回收旧区较少,增加了Full GC的风险。 增加↑:一次会回收更多的对象,但系统整体响应时间也会加长。

对于InitiatingHeapOccupancyPercent,调整参数大小的效果也不同:降低↓:提前触发Mix GC,浪费CPU。 增加↑:累积多代回收区域,增加Full GC的风险。

调优总结

系统上线前综合调优思路:

业务估算:根据每个任务的预期并发度和平均内存需求,评估需要多少台机器来承载它,每台机器需要什么配置;

容量估算:根据系统的任务处理速度,合理分配Eden区和Surivior区大小,以及老年代的内存大小;

回收器选择:对于响应优先的系统,建议使用ParNew + CMS回收器; 对于吞吐量优先、多核大内存(堆大小≥8G)的业务,建议使用G1回收器;

优化思路:让短寿命对象在MinorGC阶段被回收(同时回收后存活对象<Survivor区的50%,可以控制在新生代中保留),长寿命对象进入尽早复制老年代,不要在新生代来回复制; 尽量减少Full GC的频率,避免FGC系统的影响。

目前总结的调优过程主要是基于上线前的测试验证阶段,所以上线前我们尽量将机器的JVM参数设置为最优值。

JVM调优只是一种手段,但并不是所有的问题都可以通过JVM调优来解决。 大多数 Java 应用程序不需要 JVM 优化。 我们可以遵循以下一些原则:

通过以上原则我们发现,其实最有效的优化方式是架构和代码层面的优化,而JVM优化则是最后的手段,也可以说是对服务器配置的最后“压榨” 。

什么是 ZGC

ZGC(Z Garbage Collector)是Oracle开发的一个以低延迟为首要目标的垃圾收集器。

它是一个基于动态Region内存布局的收集器,(暂时)没有年龄生成,并使用读屏障、染色指针和内存多重映射等技术来实现并发标记排序算法。

JDK 11中新增,仍处于实验阶段,

目前使用很少,真正普及还需要时间。

如何选择垃圾收集器

实际场景中如何选择? 以下是一些建议,希望对您有所帮助:

如果你的堆大小不是很大(比如100MB),选择串行收集器通常是最有效的。 参数:-XX:+UseSerialGC。

如果你的应用程序运行在单核机器上,或者你的虚拟机只有单核,那么选择串行收集器仍然是合适的。 此时启用一些并行收集器没有任何好处。 参数:-XX:+UseSerialGC。

如果您的应用程序以“吞吐量”为先,并且对较长停顿没有特殊要求。 最好选择并行收集器。 参数:-XX:+UseParallelGC。

如果您的应用程序对响应时间要求很高并且希望减少暂停。 即使停顿1秒也会导致大量请求失败,所以选择G1、ZGC或者CMS都是合理的。 虽然这些收集器的GC暂停通常较短,但它需要一些额外的资源来处理工作,并且吞吐量通常较低。 参数:-XX:+UseConcMarkSweepGC、-XX:+UseG1GC、-XX:+UseZGC等。从上面的出发点来看,我们普通的Web服务器对于响应能力的要求非常高。

选择性实际上集中在CMS、G1和ZGC上。 对于某些定时任务,使用并行收集器是更好的选择。

为什么Hotspot要用元空间取代永久代

什么是元空间? 什么是永久代? 为什么使用元空间而不是永久代?

我们先回顾一下方法区,看一下虚拟机运行时的数据内存图,如下:

上网记录会永久存储吗_永久存储上网记录会消除吗_上网记录会永久保存在终端吗

方法区和堆一样,是每个线程共享的内存区域。 它用于存储虚拟机已加载的类信息、常量、静态变量和即时编译的代码等数据。

什么是永久代? 它与方法区有什么关系?

如果在HotSpot虚拟机上开发和部署,很多程序员将方法区称为永久代。 可以说,方法区就是规范,永久代就是Hotspot对规范的实现。 在Java7及更早的版本中,方法区是在永久代中实现的。

什么是元空间? 它与方法区有什么关系?

对于Java8,HotSpots取消了永久代,用Metaspace代替。 也就是说,方法区还在,但是实现变了,从永久代变成了元空间。

为什么永久代被元空间取代了?

永久代的方法区与堆使用的物理内存是连续的。

永久存储上网记录会消除吗_上网记录会永久存储吗_上网记录会永久保存在终端吗

永久代的大小通过以下两个参数配置:

对于永久代来说,如果动态生成的类较多,由于永久代空间配置有限,很可能会出现java.lang.OutOfMemoryError: PermGen space错误。 最典型的场景就是web开发中有很多jsp页面的时候。

JDK8之后,方法区存在于元空间(Metaspace)中。 物理内存不再与堆连续,而是直接存在于本地内存中。 理论上,机器内存的大小对应于元空间的大小。

上网记录会永久保存在终端吗_上网记录会永久存储吗_永久存储上网记录会消除吗

元空间的大小可以通过以下参数设置:

那么,为什么使用元空间而不是永久代呢?

表面上看是为了避免OOM异常。 因为PermSize和MaxPermSize通常用来设置永久代的大小,这决定了永久代的上限,但并不总是能够知道应该设置为多大。 如果使用默认值,很容易遇到OOM错误。 使用元空间时,可以加载多少类元数据不再由MaxPermSize控制,而是由系统实际可用空间控制。

什么是停止世界? 什么是 OopMap? 什么是安全点?

垃圾收集的过程涉及对象的移动。 为了保证对象引用更新的正确性,必须暂停所有用户线程。 虚拟机设计者将这样的暂停描述为 Stop The World。 也简称为 STW。

在HotSpot中,有一个称为OopMap的数据结构(映射表)。 一旦类加载动作完成,HotSpot就会计算出对象中的偏移量是什么类型的数据,并将其记录在OopMap中。

在即时编译过程中,还会在特定位置生成 OopMap,记录堆栈和寄存器中的哪些位置是引用。 这些具体地点主要在:

循环结束(非计数循环);

方法返回之前/方法调用的调用指令之后;

可能抛出异常的位置。

这些位置称为安全点。 用户程序执行时,不可能在代码指令流的任何位置停止和启动垃圾回收,但必须执行到安全点才可以暂停。

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]