2022年6月

对于程序员来说,掌握 Java 的内存管理机制并不是必须的,但它能够帮助你更好地理解 JVM 是如何处理程序中的变量和类实例的。

Java 之所以能够如此流行,自动 垃圾回收 Garbage Collection (GC)功不可没,它也是 Java 最重要的几个特性之一。在这篇文章中,我将说明为什么垃圾回收如此重要。本文的主要内容为:自动的分代垃圾回收、JVM 划分内存的依据,以及 JVM 垃圾回收的工作原理。

Java 内存分配

Java 程序的内存空间被划分为以下四个区域:

  1. 堆区 Heap :对象实例就是在这个区域分配的。不过,当我们声明一个对象时,堆中不会发生任何内存分配,只是在栈中创建了一个对象的引用而已。
  2. 栈区 Stack :方法、局部变量和类的实例变量就是在这个区域分配的。
  3. 代码区 Code :这个区域存放了程序的字节码。
  4. 静态区 Static :这个区域存放了程序的静态数据和静态方法。

什么是自动垃圾回收?

自动垃圾回收是这样一个过程:首先,堆中的所有对象会被分类为“被引用的”和“未被引用的”;接着,“未被引用的对象”就会被做上标记,以待之后删除。其中,“被引用的对象”是指程序中的某一部分仍在使用的对象,“未被引用的对象”是指目前没有正在被使用的对象。

许多编程语言,例如 C 和 C++,都需要程序员手动管理内存的分配和释放。在 Java 中,这一过程是通过垃圾回收机制来自动完成的(尽管你也可以在代码中调用 system.gc(); 来手动触发垃圾回收)。

垃圾回收的基本步骤如下:

1、标记已使用和未使用的对象

在这一步骤中,已使用和未使用的对象会被分别做上标记。这是一个及其耗时的过程,因为需要扫描内存中的所有对象,才能够确定它们是否正在被使用。

标记已使用和未使用的对象

2、扫描/删除对象

有两种不同的扫描和删除算法:

简单删除(标记清除):它的过程很简单,我们只需要删除未被引用的对象即可。但是,后续给新对象分配内存就会变得很困难了,因为可用空间被分割成了一块块碎片。

标记清除的过程

删除压缩(标记整理):除了会删除未被引用的对象,我们还会压缩被引用的对象(未被删除的对象)。这样以来,新对象的内存分配就相对容易了,并且内存分配的效率也有了提升。

标记整理的过程

什么是分代垃圾回收,为什么需要它?

正如我们在“扫描删除”模型中所看到的,一旦对象不断增长,我们就很难扫描所有未使用的对象以回收内存。不过,有一项实验性研究指出,在程序执行期间创建的大多数对象,它们的存活时间都很短。

既然大多数对象的存活时间都很短,那么我们就可以利用这个事实,从而提升垃圾回收的效率。该怎么做呢?首先,JVM 将内存划分为不同的“代”。接着,它将所有的对象都分类到这些内存“代”中,然后对这些“代”分别执行垃圾回收。这就是“分代垃圾回收”。

堆内存的“代”和分代垃圾回收过程

为了提升垃圾回收中的“标记清除”的效率,JVM 将对内存划分成以下三个“代”:

  • 新生代 Young Generation
  • 老年代 Old Generation
  • 永久代 Permanent Generation

Hotspot 堆内存结构

下面我将介绍每个“代”及其主要特征。

新生代

所有创建不久的对象都存放在这里。新生代被进一步分为以下两个区域:

  1. 伊甸区 Eden :所有新创建的对象都在此处分配内存。
  2. 幸存者区 Survivor ,分为 S0 和 S1:经历过一次垃圾回收后,仍然存活的对象会被移动到两个幸存者区中的一个。

对象分配

在新生代发生的分代垃圾回收被称为 “ 次要回收 Minor GC ”(LCTT 译注:也称为“ 新生代回收 Young GC ”)。Minor GC 过程中的每个阶段都是“ 停止世界 Stop The World ”(STW)的,这会导致其他应用程序暂停运行,直到垃圾回收结束。这也是次要回收更快的原因。

一句话总结:伊甸区存放了所有新创建的对象,当它的可用空间被耗尽,第一次垃圾回收就会被触发。

填充伊甸区

次要回收:在该垃圾回收过程中,所有存活和死亡的对象都会被做上标记。其中,存活对象会被移动到 S0 幸存者区。当所有存活对象都被移动到了 S0,未被引用的对象就会被删除。

拷贝被引用的对象

S0 中的对象年龄为 1,因为它们挺过了一次次要回收。此时,伊甸区和 S1 都是空的。

每当完成清理后,伊甸区就会再次接受新的存活对象。随着时间的推移,伊甸区和 S0 中的某些对象被宣判死亡(不再被引用),并且伊甸区的可用空间也再次耗尽(填满了),那么次要回收 又将再次被触发。

对象年龄增长

这一次,伊甸区和 S0 中的死亡和存活的对象会被做上标记。其中,伊甸区的存活对象会被移动到 S1,并且年龄增加至 1。S0 中的存活对象也会被移动到 S1,并且年龄增加至 2(因为它们挺过了两次次要回收)。此时,伊甸区和 S0 又是空的了。每次次要回收之后,伊甸区和两个幸存者区中的一个都会是空的。

新对象总是在伊甸区被创建,周而复始。当下一次垃圾回收发生时,伊甸区和 S1 都会被清理,它们中的存活对象会被移动到 S0 区。每次次要回收之后,这两个幸存者区(S0 和 S1)就会交换一次。

额外年龄增长

这个过程会一直进行下去,直到某个存活对象的年龄达到了某个阈值,然后它就会被移动到一个叫做“老年代”的地方,这是通过一个叫做“晋升”的过程来完成的。

使用 -Xmn 选项可以设置新生代的大小。

老年代

这个区域存放着那些挺过了许多次次要回收,并且达到了某个年龄阈值的对象。

晋升

在上面这个示例图表中,晋升的年龄阈值为 8。在老年代发生的垃圾回收被称为 “ 主要回收 Major GC ”。(LCTT 译注:也被称为“ 全回收 Full GC ”)

使用 -Xms-Xmx 选项可以分别设置堆内存大小的初始值和最大值。(LCTT 译注:结合上面的 -Xmn 选项,就可以间接设置老年代的大小了。)

永久代

永久代存放着一些元数据,它们与应用程序、Java 标准环境以及 JVM 自用的库类及其方法相关。JVM 会在运行时,用到了什么类和方法,就会填充相应的数据。当 JVM 发现有未使用的类,就会卸载或是回收它们,从而为正在使用的类腾出空间。

使用 -XX:PermGen-XX:MaxPerGen 选项可以分别设置永久代大小的初始值和最大值。

元空间

Java 8 引入了 元空间 Metaspace ,并用它替换了永久代。这么做的好处是自动调整大小,避免了 内存不足 OutOfMemory (OOM)错误。

总结

本文讨论了各种不同的 JVM 内存“代”,以及它们是如何在分代垃圾回收算法中起作用的。对于程序员来说,掌握 Java 的内存管理机制并不是必须的,但它能够帮助你更好地理解 JVM 处理程序中的变量和类实例的方式。这种理解使你能够规划和排除代码故障,并理解特定平台固有的潜在限制。

正文配图来自:Jayashree Huttanagoudar,CC BY-SA 4.0


via: https://opensource.com/article/22/6/garbage-collection-java-virtual-machine

作者:Jayashree Huttanagoudar 选题:lkxed 译者:lkxed 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

谷歌表示该让小企业长期用户付费了

谷歌表示旧的免费版办公套件的长期用户必须开始每月支付费,通常是每个企业邮件地址 6 美元/月。到 6 月 27 日还未自愿切换到付费服务的企业将被自动转为付费服务。如果他们在 8 月 1 日之前没有付费,帐户将被暂停使用。受到这一变化影响的小企业主们表示,他们对谷歌处理这一问题的方式感到失望。他们忍不住会觉得这家拥有数十亿美元利润的大公司就为了一点点钱,而压榨这些最早使用谷歌应用工作的“小虾米”企业。

消息来源:纽约时报
老王点评:地主通常都会说,地主家也没余粮啊。但是让这些习惯了免费套餐的人来说,就很难受了,甚至这不是钱的事,而是心理感受不好。

智能灯的芯片就能运行《毁灭战士》游戏

一位软件工程师在阅读了关于《毁灭战士》据称可以在验孕棒上运行的新闻后,开始了这个项目。他拆下了一台 15 美元的宜家智能台灯的电脑芯片,用它建立了一个小型化的《毁灭战士(Doom)》游戏系统。它运行的是精简版的《毁灭战士》,需要较少的内存。来自宜家灯的芯片有足够的处理能力,可以在一个廉价的 160×128 像素的显示屏上以每秒 35 帧的速度进行游戏。

消息来源:PCMag
老王点评:好吧,我想象不出来下一步会在什么上面运行《毁灭战士》了,或许是在土豆上?

Cloudflare 出现宕机,1.1.1.1 无法解析域名

北京时间 6 月 20 日下午,Cloudflare 出现了宕机的情况。根据监测信息显示,包括 Discord、Shopify、Medium、Register 等诸多网站和服务都出现了故障。对于使用 Cloudflare 的 DNS 查询服务的用户来说,影响最为严重,他们在中断期间根本无法访问任何网站。

消息来源:Tech Crunch
老王点评:Cloudflare 的防 DDoS 服务是很好,但是这种大型服务总断网也受不了啊。

JavaScript 是为 Web 而生的,但它可以做的事远不止于此。本文将带领你了解它的基础知识,然后你可以下载我们的备忘清单,以便随时掌握详细信息。

JavaScript 是一种充满惊喜的编程语言。许多人第一次遇到 JavaScript 时,它通常是作为一种 Web 语言出现的。所有主流浏览器都有一个 JavaScript 引擎;并且,还有一些流行的框架,如 JQuery、Cash 和 Bootstrap 等,它们可以帮助简化网页设计;甚至还有用 JavaScript 编写的编程环境。它似乎在互联网上无处不在,但事实证明,它对于 Electron 等项目来说也是一种有用的语言。Electron 是一个构建跨平台桌面应用程序的开源工具包,它使用的语言就是 JavaScript。

JavaScript 语言的用途多到令人惊讶,它拥有各种各样的库,而不仅仅是用于制作网站。它的基础知识十分容易掌握,因此,它可以作为一个起点,助你跨出构建你想象中的东西的第一步。

安装 JavaScript

随着你的 JavaScript 水平不断提高,你可能会发现自己需要高级的 JavaScript 库和运行时环境。不过,刚开始学习的时候,你是根本不需要安装 JavaScript 环境的。因为所有主流的 Web 浏览器都包含一个 JavaScript 引擎来运行代码。你可以使用自己喜欢的文本编辑器编写 JavaScript,将其加载到 Web 浏览器中,接着你就能看到代码的作用。

上手 JavaScript

要编写你的第一个 JavaScript 代码,请打开你喜欢的文本编辑器,例如 AtomVSCode 等。因为它是为 Web 开发的,所以 JavaScript 可以很好地与 HTML 配合使用。因此,我们先来尝试一些基本的 HTML:

<html>
  <head>
    <title>JS</title>
  </head>
  <body>
    <p id="example">Nothing here.</p>
  </body>
</html>

保存这个文件,然后在 Web 浏览器中打开它。

浏览器中显示的 HTML

要将 JavaScript 添加到这个简单的 HTML 页面,你可以创建一个 JavaScript 文件并在页面的 <head> 中引用它,或者只需使用 <script> 标记将 JavaScript 代码嵌入 HTML 中。在这个例子中,我嵌入了下面的代码:

<html>
  <head>
    <title>JS</title>
  </head>
  <body>
    <p id="example">Nothing here.</p>

    <script>
      let myvariable = "Hello world!";

      document.getElementById("example").innerHTML = myvariable;
    </script>

  </body>
</html>

在浏览器中重新加载页面。

在浏览器中显示带有 JavaScript 的 HTML

如你所见,<p> 标签仍然包含字符串 "Nothing here",但是当它被渲染时,JavaScript 会改变它,使其包含 "Hello world"。是的,JavaScript 具有重建​​(或只是帮助构建)网页的能力。

这个简单脚本中的 JavaScript 做了两件事。首先,它创建一个名为 myvariable 的变量,并将字符串 "Hello world!" 放置其中。然后,它会在当前文档(浏览器呈现的网页)中搜索 ID 为 example 的所有 HTML 元素。当它找到 example 时,它使用了 innerHTML 属性将 HTML 元素的内容替换为 myvariable 的内容。

当然,我们也可以不用自定义变量。因为,使用动态创建的内容来填充 HTML 元素也是容易的。例如,你可以使用当前时间戳来填充它:

<html>
  <head>
    <title>JS</title>
  </head>
  <body>
    <p id="example">Date and time appears here.</p>

    <script>
      document.getElementById("example").innerHTML = Date();
    </script>
    
  </body>
</html>

重新加载页面,你就可以看到在呈现页面时生成的时间戳。再重新加载几次,你可以观察到秒数会不断增加。

JavaScript 语法

在编程中, 语法 syntax 指的是如何编写句子(或“行”)的规则。在 JavaScript 中,每行代码必须以分号(;)结尾,以便运行代码的 JavaScript 引擎知道何时停止阅读。(LCTT 译注:从实用角度看,此处的“必须”其实是不正确的,大多数 JS 引擎都支持不加分号。Vue.js 的作者尤雨溪认为“没有应该不应该,只有你自己喜欢不喜欢”,他同时表示,“Vue.js 的代码全部不带分号”。详情可以查看他在知乎上对于此问题的 回答。)

单词(或 字符串 strings )必须用引号(")括起来,而数字(或 整数 integers )则不用。

几乎所有其他东西都是 JavaScript 语言的约定,例如变量、数组、条件语句、对象、函数等等。

在 JavaScript 中创建变量

变量是数据的容器。你可以将变量视为一个盒子,你在其中放置数据,以便与程序的其他部分共享它。要在 JavaScript 中创建变量,你可以选用关键字 letvar 中的一个,请根据你打算如何使用变量来选择:var 关键字用于创建一个供整个程序使用的变量,而 let 只为特定目的创建变量,通常在函数或循环的内部使用。(LCTT 译注:还有 const 关键字,它用于创建一个常量。)

JavaScript 内置的 typeof 函数可以帮助你识别变量包含的数据的类型。使用第一个示例,你可以修改显示文本,来显示 myvariable 包含的数据的类型:

<string>
let myvariable = "Hello world!";
document.getElementById("example").innerHTML = typeof(myvariable);
</string>

接着,你就会发现 Web 浏览器中显示出 “string” 字样,因为该变量包含的数据是 "Hello world!"。在 myvariable 中存储不同类型的数据(例如整数),浏览器就会把不同的数据类型打印到示例网页上。尝试将 myvariable 的内容更改为你喜欢的数字,然后重新加载页面。

在 JavaScript 中创建函数

编程中的函数是独立的数据处理器。正是它们使编程得以 模块化。因为函数的存在,程序员可以编写通用库,例如​​,调整图像大小或统计时间花费的库,以供其他和你一样的程序员在他们的代码中使用。

要创建一个函数,你可以为函数提供一个自定义名称,后面跟着用大括号括起来的、任意数量的代码。

下面是一个简单的网页,其中包含了一个剪裁过的图像,还有一个分析图像并返回真实图像尺寸的按钮。在这个示例代码中,<button> 这个 HTML 元素使用了 JavaScript 的内置函数 onclick 来检测用户交互,它会触发一个名为 get_size 的自定义函数。具体代码如下:

<html>
  <head>
    <title>Imager</title>
  </head>
  <body>

    <div>
      <button onclick="get_size(document.getElementById('myimg'))">
        Get image size
    </button>
    </div>
    
    <div>
      <img style="width: 15%" id="myimg" src="penguin.png" />
    </div>
   
    <script>
      function get_size(i) {
        let w = i.naturalWidth;
        let h = i.naturalHeight;
        alert(w + " by " + h);
      }
    </script>
    
  </body>
</html>

保存这个文件,并将其加载到 Web 浏览器中以尝试这段代码。

自定义的 get_size 函数返回了图像尺寸

使用 JavaScript 的跨平台应用程序

你可以从代码示例中看到,JavaScript 和 HTML 紧密协作,从而创建了有凝聚力的用户体验。这是 JavaScript 的一大优势。当你使用 JavaScript 编写代码时,你继承了现代计算中最常见的用户界面之一,而它与平台无关,那就是 Web 浏览器。你的代码本质上是跨平台的,因此你的应用程序,无论是简单的图像大小分析器还是复杂的图像编辑器、视频游戏,或者你梦想的任何其他东西,都可以被所有人使用,无论是通过 Web 浏览器,还是桌面(如果你同时提供了一个 Electron 应用)。

学习 JavaScript 既简单又有趣。网络上有很多网站提供了相关教程,还有超过一百万个 JavaScript 库可帮助你与设备、外围设备、物联网、服务器、文件系统等进行交互。在你学习的过程中,请将我们的 JavaScript 备忘单 放在身边,以便记住语法和结构的细节。

JavaScript 备忘单

via: https://opensource.com/article/21/7/javascript-cheat-sheet

作者:Seth Kenlon 选题:lkxed 译者:lkxed 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过这些 Ansible 文章扩展你的知识和技能。

 title=

我希望能够激发刚刚接触 Ansible 的初学者的兴趣。这里有一系列总结文章,我已将其包括在内,以供你随意后续查阅。

适合初学者的 Ansible

这五篇文章对于 Ansible 新手来说是一个非常好的起点。前三篇文章由 Seth Kenlon 撰写。

  • 如果你不了解 Ansible ,现在可以做这 7 件事 来入手。这是很好的入门指导,它收集了用于管理硬件、云、容器等的链接。
  • 在 《编排与自动化有何区别?》 这篇文章中,你会学到一些术语和技术路线,将会激发你对 Ansible 感兴趣。
  • 文章 《如何用 Ansible 安装软件》 覆盖了一些脚本概念和一些 Ansible 的好惯例,给出了一些本地或远程管理软件包的案例。
  • 我编写 Ansible 剧本时学到的 3 个教训 中,使自己养成 Jeff Geerling 所传授的好习惯,他是一位真正的 Ansible 资深人士。源代码控制、文档、测试、简化和优化是自动化成功的关键。
  • 我使用 Ansible 的第一天》 介绍了记者 David Both 在解决重复性开发任务时的思考过程。这篇文章从 Ansible 的基础开始,并说明了一些简单的操作和任务。

尝试 Ansible 项目

一旦你掌握了基础和并拥有良好习惯,就可以开始一些具体主题和实例了。

提升你的 Ansible 技巧

Kubernetes 是近来的热门话题,以下文章提供了一些很好的示例来学习新技能。

我希望你的 Ansible 旅程已经开始,并能常从这些文章中充实自己。


via: https://opensource.com/article/21/1/ansible

作者:James Farrell 选题:lujun9972 译者:Donkey 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

自 2016 年开源以来,Mattermost 一直在开发一个具有不断增加的用例的消息传递平台。6 月 16 日,Mattermost 7.0 平台发布,其中包括了新的语音呼叫、工作流模板和用于开源技术的应用框架。新版本扩展了 2021 年 10 月发布的 6.0 版本引入的功能。一直以来,Mattermost 都在与包括 Slack、Atlassian 和 Asana 在内的几家大公司,竞争不断增长的协作工具市场。另一方面,Mattermost 侧重于对开发者的支持,尽管该平台也可用于安全和 IT 运营。

Mattermost 的软件同时提供有商业版和开源版,目前它们都升级到了 7.0 版。Tien 解释说,Mattermost 的商业平台是建立在开源基础上的。在开放核心模型中,开源版作为软件的基础或核心,专有的企业功能则内置于商业版中。合规性、规模性和高级配置是 Mattermost 的关键企业功能。Tien 声称,开源版本对于中小型团队来说已经足够了。他认为,拥有 500 名或更多用户的团队才需要考虑使用商业版。

Tien 认为开源也关乎社区贡献。Mattermost 开源项目有超过 4000 名个人贡献者,他们贡献了超过 30000 行代码。

以前,Mattermost 依赖集成第三方呼叫服务(例如 Zoom)来启用语音呼叫功能。在 7.0 版本中,它通过开源 WebRTC 协议引入了呼叫功能的直接集成,所有现代 Web 浏览器都支持该协议。直接集成呼叫功能的目标是为协作提供单一平台,这符合 Tien 对该平台的总体愿景。现在,除了提供集成工具以实现协作之外,该平台还会增加“工作流模板”功能,以帮助(用户)组织构建可重复的流程。

工作流概念采用了 剧本 playbook ,其中包含了为“特定类型的操作”所执行的动作和操作的清单。例如,在发生服务故障或网络安全事件时,公司可以为事件响应创建工作流模板。

这个清单可以链接到 Mattermost 操作 operation ,例如让特定用户发起呼叫,并协助生成报告。Tien 表示,Mattermost 还与常见的开发者工具集成,并且工作流模板的功能将随着时间的推移而扩展,以便使用第三方工具来实现更多自动化。


via: https://www.opensourceforu.com/2022/06/mattermost-extends-workflow-platform-with-7-0-release/

作者:Laveesh Kocher 选题:lkxed 译者:lkxed 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Ubuntu 22.04 干掉内存占用超出的应用引来批评

在 Ubuntu 邮件列表中,用户们正在讨论一个普遍现象:在没有任何迹象表明有问题的情况下,像 Firefox、Chrome 和 VS Code 这样的大型应用程序会突然被干掉。这是因为 Ubuntu 22.04 中引入了 systemd-oomd,当它检测到内存压力变得有点大时,就会进行干预,从而干掉那些占用内存较大的应用程序。问题是,它似乎被触发得太频繁了,即使内存没有到了必须处置的地步,也会杀死应用程序。而且没有任何警告,也不给你保存数据的机会,甚至应用被杀死后也不会有任何说明。参与讨论的 Canonical 的工程师表示将会修改一些触发条件。

消息来源:OMG! Ubuntu!
老王点评:作为一个 LTS 版本却表现的如此不可靠,即便说这些阈值设置不够合理,突然干掉应用的做法的用户体验也太糟糕了。

Android 13 终于原生支持 exFAT 驱动器

在三星的 exFAT 驱动被合入到 Linux 5.7 后,就可以在 Linux 中原生访问 exFAT 文件系统了。但谷歌维护的安卓通用内核(ACK)长期以来都是基于 Linux 5.4 的,直到 5.10 才形成了一个新的分支。但由于一些限制,基于 Linux 5.10 内核的 Android 12 设备还无法支持 exFAT。随着 Android 13 的到来,有研究人员发现,谷歌 Pixel 系列移动设备用户,能够原生处理 exFAT 磁盘上大于 4GB 的单个文件了。一旦谷歌在 Android 13 上正式完成了部署,其它 OEM 厂商也将能够直接受益于 Android 开源项目(AOSP)的 exFAT 支持。

消息来源:Android Police
老王点评:终于有了支持,不过,我没想到是因为安卓的内核太老而不支持。

腾讯宣布将 5000 万核的应用迁移到腾讯云

据报道,腾讯在 2018 年意识到其众多服务各自建立了自己的技术孤岛后,开始考虑这个问题,探索如何将腾讯的服务转移到腾讯云上。现在腾讯宣布,它已经将消耗 5000 万个内核的工作负载转移到其云端,迄今为止节省了 4.46 亿美元,整体效率比行业标准高出 30%。新基础设施的利用率为 50%,带宽增加了 7.6 倍,并增强了 DDoS 保护。

消息来源:The Register
老王点评:对于这种大型 IT 企业来说,能用上自家的云,不仅能省钱,而且客户才会信任你的公有云服务。