<?xml version="1.0" encoding="utf-8"?>
    <feed xmlns="http://www.w3.org/2005/Atom">
        
            <title type="text">青云之上，步步登高</title>
        

        
            
        
        <updated>2024-09-10T13:53:59+08:00</updated>

        
            <id>https://blog.554321.xyz</id>
        
        
            <link rel="alternate" type="text/html" href="https://blog.554321.xyz"/>
            <link rel="self" type="application/atom+xml" href="https://blog.554321.xyz/atom.xml"/>
        
        <rights>Copyright © 2026, 青云之上，步步登高</rights>
        <generator uri="https://go-sonic.org/" version="v1.1.4">Sonic</generator>
        
            
                <entry>
                    <title><![CDATA[深究Javascript原型的原理和作用]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/Javascript"/>
                    <id>tag:https://blog.554321.xyz,2024-09-10:Javascript</id>
                    <published>2024-09-10T13:53:59+08:00</published>
                    <updated>2024-09-10T13:53:59+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<p>在 JavaScript 中，原型（prototype）是对象的一个重要特性，提供了继承和共享属性的机制。以下是原型的一些关键作用：</p><h3 id="1.%E7%BB%A7%E6%89%BF%E5%92%8C%E5%85%B1%E4%BA%AB%E5%B1%9E%E6%80%A7%EF%BC%9A" tabindex="-1">1.继承和共享属性：</h3><ul><li>原型允许对象共享属性和方法，从而避免了每个对象都重复存储相同的属性或方法。例如，如果你创建了一个构造函数和相关的原型对象，所有通过该构造函数创建的实例都可以访问原型上的方法和属性。</li></ul><h3 id="2.%E8%8A%82%E7%9C%81%E5%86%85%E5%AD%98%EF%BC%9A" tabindex="-1">2.节省内存：</h3><ul><li>通过将方法和属性定义在原型上，而不是在每个实例中定义，JavaScript 能够节省内存。这是因为所有实例共享同一个原型对象，从而避免了每个实例重复存储相同的函数。</li></ul><h3 id="3.%E5%8A%A8%E6%80%81%E6%89%A9%E5%B1%95%E5%AF%B9%E8%B1%A1%EF%BC%9A" tabindex="-1">3.动态扩展对象：</h3><ul><li>你可以在运行时修改对象的原型，这使得在开发过程中动态扩展对象的功能变得更加灵活。例如，可以向原型添加新方法，所有使用该原型的对象都可以立即使用这些新方法。</li></ul><h3 id="4.%E5%AE%9E%E7%8E%B0%E7%BB%A7%E6%89%BF%EF%BC%9A" tabindex="-1">4.实现继承：</h3><ul><li>原型链是实现 JavaScript 中继承机制的基础。通过将一个对象的原型设置为另一个对象，你可以实现对象之间的继承关系，使得子对象能够继承父对象的属性和方法。</li></ul><h3 id="5.%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%A1%88%E4%BE%8B%3A" tabindex="-1">5.原型链案例:</h3><pre><code class="language-">function Animal(name) {  this.name = name;}Animal.prototype.say = function() {  console.log(&#96;${this.name} makes a sound.&#96;);};function Dog(name) {  Animal.call(this, name); // 调用父类构造函数}// 设置 Dog 的原型为 Animal 的实例Dog.prototype = Object.create(Animal.prototype);Dog.prototype.constructor = Dog; // 修复 constructor 指向Dog.prototype.bark = function() {  console.log(&#96;${this.name} barks.&#96;);};const myDog = new Dog(&#39;Rover&#39;);myDog.say(); // 输出: Rover makes a sound.myDog.bark(); // 输出: Rover barks.</code></pre>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[适用低配置边缘终端的next.js全栈框架模板]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/nextjs"/>
                    <id>tag:https://blog.554321.xyz,2024-09-10:nextjs</id>
                    <published>2024-09-10T12:42:01+08:00</published>
                    <updated>2024-09-10T12:42:01+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h3 id="%E4%BB%8B%E7%BB%8D" tabindex="-1">介绍</h3><ul><li>这是一个 Next.js 的脚手架模板，集成了 Prisma 作为 ORM，使用 SQLite 作为默认数据库，并且包含了日志采集功能。该模板为开发者提供了一个开箱即用的全栈框架，便于快速搭建具有数据库支持和日志监控的应用程序。Prisma 简化了数据库操作，而 SQLite 则作为轻量级的存储解决方案，适合快速原型设计和小型项目。日志采集功能则有助于在开发和生产环境中对应用的运行状态进行监控。</li></ul><h3 id="%E4%BC%98%E5%8A%BF" tabindex="-1">优势</h3><ul><li>现在越来越多的传统项目从C/S转为B/S，轻全栈框架可以专注GUI显示和C++高低搭配进行业务调度</li></ul><h3 id="%E9%93%BE%E6%8E%A5" tabindex="-1">链接</h3><ul><li><a href="https://github.com/loranceliu/next.js">点击</a></li></ul>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[使用C++多线程开发的后端连接脚手架]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/shi-yong-c-duo-xian-cheng-kai-fa-de-ji-qi-shi-jue-qian-hou-duan-kai-fa-jiao-shou-jia"/>
                    <id>tag:https://blog.554321.xyz,2024-09-10:shi-yong-c-duo-xian-cheng-kai-fa-de-ji-qi-shi-jue-qian-hou-duan-kai-fa-jiao-shou-jia</id>
                    <published>2024-09-10T12:26:39+08:00</published>
                    <updated>2024-09-10T12:26:39+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h3 id="%E4%BB%8B%E7%BB%8D" tabindex="-1">介绍</h3><ul><li>这是一个用c++开发的WebSocket 事件调度框架不仅用于 AI 前后端调用与交互，还集成了线程池机制，以提升性能和并发处理能力。通过使用线程池，框架能够高效处理大量的并发事件，避免频繁创建和销毁线程带来的开销，从而在保证实时性和低延迟的同时，提高了系统的可扩展性和稳定性。这使得框架在处理复杂的 AI 任务时，能够更好地分配计算资源，确保高效的事件调度和响应</li></ul><h3 id="%E4%BC%98%E5%8A%BF" tabindex="-1">优势</h3><ul><li>解决很多开发者不擅长网络开发问题，只要专注于算法实现部分就可以了</li><li>采用线程池，减少了线程频繁切换</li></ul><h3 id="%E9%93%BE%E6%8E%A5%3A" tabindex="-1">链接:</h3><ul><li><a href="https://github.com/loranceliu/ws">点击</a></li></ul>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[模拟Mysql slave开发的一款mysql数据同步工具]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/mo-ni-mysqlslave-kai-fa-de-yi-kuan-mysql-shu-ju-tong-bu-gong-ju"/>
                    <id>tag:https://blog.554321.xyz,2024-09-10:mo-ni-mysqlslave-kai-fa-de-yi-kuan-mysql-shu-ju-tong-bu-gong-ju</id>
                    <published>2024-09-10T12:08:04+08:00</published>
                    <updated>2024-09-10T12:08:04+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h3 id="%E4%BB%8B%E7%BB%8D" tabindex="-1">介绍</h3><ul><li>这个是一款使用 Golang 构建的数据库同步工具，专门用于同步 MySQL 数据库。该工具基于 MySQL 的 binlog（binary log）来捕获数据变更，通过模拟 MySQL 的 slave 角色，实现实时的数据库同步。这种方式允许你的工具以非侵入性的方式监听和解析 binlog，从而跟踪数据库中的插入、更新和删除操作，并将这些变更同步到目标数据库或其他系统中。</li></ul><h3 id="%E9%85%8D%E7%BD%AE" tabindex="-1">配置</h3><pre><code class="language-">        Mysql:           Host: 192.168.2.204           Port: 30306           User: root           Pwd: 123456        Slave:          ServerID: 1000   //ID          Flavor: mysql             Binlog: mysql-bin.000002 //binlog-name          Pos: 1  //start position          LoadNew: false  //is load new          LoadPath: &quot;/Users/liu/Downloads/a1/&quot;</code></pre><h3 id="%E9%93%BE%E6%8E%A5%3A" tabindex="-1">链接:</h3><ul><li><a href="https://github.com/loranceliu/data-sync">点击</a></li></ul>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[基于Golang开发的iot-x网络接入层框架]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/ji-yu-golang-kai-fa-de-iot-x-wang-luo-jie-ru-ceng-kuang-jia"/>
                    <id>tag:https://blog.554321.xyz,2024-09-10:ji-yu-golang-kai-fa-de-iot-x-wang-luo-jie-ru-ceng-kuang-jia</id>
                    <published>2024-09-10T10:39:54+08:00</published>
                    <updated>2024-09-10T10:39:54+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h3 id="%E4%BB%8B%E7%BB%8D" tabindex="-1">介绍</h3><ul><li>该开源是一个基于 Golang 开发的网络接入层框架，采用了 Protobuf 进行数据序列化，并集成了 RabbitMQ 等技术。它具备灵活的部署方式，既可以支持单点部署，也可以轻松扩展为集群部署。该框架旨在提供高效、稳定的网络接入服务，能够满足多样化的业务需求，适用于高并发、分布式系统等场景。</li></ul><h3 id="%E4%BC%98%E5%8A%BF" tabindex="-1">优势</h3><ul><li>以较轻的技术栈代替传统netty或c系语言高复杂度</li><li>高可用，并且并发连接较高</li></ul><h3 id="%E9%93%BE%E6%8E%A5%3A" tabindex="-1">链接:</h3><ul><li><a href="https://github.com/loranceliu/iot-x">点击</a></li></ul>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[基于Golang和React Native开发的资金往来APP]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/ji-yu-golang-he-reactnative-kai-fa-de-zi-jin-wang-lai-app"/>
                    <id>tag:https://blog.554321.xyz,2024-09-09:ji-yu-golang-he-reactnative-kai-fa-de-zi-jin-wang-lai-app</id>
                    <published>2024-09-09T20:59:41+08:00</published>
                    <updated>2024-09-09T20:59:41+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h3 id="%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D" tabindex="-1">项目介绍</h3><p>此项目初衷来源于我岳父这边的生活琐事，在湖南农村人情往来特别严重，特别是亲戚往来，少则几千多则上万，此APP让自己的资金往来一目了然，杜绝赈酒恶习也是势在必行.</p><h3 id="%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84" tabindex="-1">技术架构</h3><ul><li>后端采用比较轻的golang实现，基于gin、gorm等框架组成</li><li>APP为跨平台，采用的是React Native实现</li></ul><h3 id="%E5%8A%9F%E8%83%BD%E5%B1%95%E7%A4%BA" tabindex="-1">功能展示</h3><div style="display: flex; flex-wrap: wrap;">  <div style="flex: 1 1 33.33%; padding: 5px;">    <img src="https://oss.554321.xyz/blog/701725893815_.pic.jpg" style="width: 100%;" />  </div>  <div style="flex: 1 1 33.33%; padding: 5px;">    <img src="https://oss.554321.xyz/blog/691725893789_.pic.jpg" style="width: 100%;" />  </div>  <div style="flex: 1 1 33.33%; padding: 5px;">    <img src="https://oss.554321.xyz/blog/681725893787_.pic.jpg" style="width: 100%;" />  </div>  <div style="flex: 1 1 33.33%; padding: 5px;">    <img src="https://oss.554321.xyz/blog/651725893780_.pic.jpg" style="width: 100%;" />  </div>   <div style="flex: 1 1 33.33%; padding: 5px;">     <img src="https://oss.554321.xyz/blog/671725893784_.pic.jpg" style="width: 100%;" /> </div>  <div style="flex: 1 1 33.33%; padding: 5px;">    <img src="https://oss.554321.xyz/blog/relation-2024-09-09.jpg" style="width: 100%;" />  </div></div><h3 id="%E9%93%BE%E6%8E%A5%E5%9C%B0%E5%9D%80" tabindex="-1">链接地址</h3><ul><li><a href="https://github.com/loranceliu/relation">后端</a></li><li><a href="https://github.com/loranceliu/relation-app">APP</a></li></ul>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[细谈Mongodb分片逻辑]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/xi-tan-mongodb-fen-pian-luo-ji"/>
                    <id>tag:https://blog.554321.xyz,2024-09-09:xi-tan-mongodb-fen-pian-luo-ji</id>
                    <published>2024-09-09T14:41:45+08:00</published>
                    <updated>2024-09-09T14:41:45+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<p>MongoDB 的分片（Sharding）是一种数据库架构模式，它用于在多个服务器上水平扩展数据的存储和计算能力。通过分片，MongoDB 将集合的数据分布到多个分片（shard）上，每个分片存储集合的一个子集。这使得 MongoDB 能够处理大量数据，以及随着数据量的增长而提高读写操作的性能。</p><div align=center>  <img src="https://oss.554321.xyz/blog/mongodb-2024-09-09.png" /></div><h3 id="1.-%E5%88%86%E7%89%87%E9%94%AE%EF%BC%88shard-key%EF%BC%89" tabindex="-1">1. 分片键（Shard Key）</h3><ul><li>分片的核心是分片键，它是用于确定如何将数据分散到不同分片上的字段或字段组合。当插入或查询数据时，MongoDB 会使用分片键来决定操作应该定位到哪个分片上。分片键的选择非常关键，因为它会影响数据的分布和查询的性能。</li></ul><h3 id="2.-%E5%88%86%E7%89%87%E8%BF%87%E7%A8%8B" tabindex="-1">2. 分片过程</h3><ul><li>自动分片：MongoDB 支持自动分片，其中 MongoDB 根据分片键将数据自动分布到不同的分片上。这是通过 MongoDB 的分片集群架构来实现的，其中包括配置服务器（config servers）、分片（shards）和路由服务器（mongos 实例）。</li><li>数据迁移：当数据增长并超过分片容量时，MongoDB 会自动在分片之间迁移数据块（chunks），以保持负载平衡。这种迁移是由 MongoDB 的分片平衡器自动管理的。</li></ul><h3 id="3.-%E5%88%86%E7%89%87%E7%B1%BB%E5%9E%8B" tabindex="-1">3. 分片类型</h3><h4 id="3.1-%E8%8C%83%E5%9B%B4%E5%88%86%E7%89%87%EF%BC%9A" tabindex="-1">3.1 范围分片：</h4><ul><li>最常用的分片策略，其中根据分片键的范围将数据分配到不同的分片上。例如，如果一个集合使用年龄作为分片键，那么 MongoDB 可以将儿童、青年和老年人的数据分布到不同的分片上.</li><li>优势是范围查询不需要广播，可以直接定位到某个分片.</li></ul><h4 id="3.2-%E5%93%88%E5%B8%8C%E5%88%86%E7%89%87%EF%BC%9A" tabindex="-1">3.2 哈希分片：</h4><ul><li>适用于分片键具有随机性或没有自然顺序的场景。通过将分片键的哈希值分配到不同的分片上，MongoDB 可以确保数据的均匀分布。</li><li>优势数据分布更均衡，插入性能更好。</li></ul><h3 id="4.-%E5%88%86%E7%89%87%E6%9E%B6%E6%9E%84" tabindex="-1">4. 分片架构</h3><ul><li>配置服务器(config server)：存储分片集群的元数据和配置信息，包括分片的位置、分片的范围以及每个分片上数据的分配。</li><li>分片(shared)：存储实际数据的服务器。它们可以是任何MongoDB实例，可以配置为副本集以提供高可用性和数据冗余。</li><li>路由服务器（mongos）：客户端连接到路由服务器，而不是直接连接到分片。路由服务器作为分片集群的入口点，处理来自客户端的请求，并根据分片键将请求路由到正确的分片上。</li></ul><h3 id="5.-%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB" tabindex="-1">5. 读写分离</h3><ul><li>在分片集群中，可以通过配置来实现读写分离，即将读请求路由到不同的分片上，以提高读操作的吞吐量。这通常通过在应用程序中使用连接字符串的适当选项或在查询时指定读偏好（read preference）来实现。</li></ul><h3 id="%E6%80%BB%E7%BB%93" tabindex="-1">总结</h3><p>MongoDB 的分片提供了一种灵活的方式来扩展数据库的性能和容量。通过正确配置分片键、分片类型和分片架构，MongoDB 可以高效地处理大规模数据集，并支持高可用性和故障恢复。在设计和部署分片集群时，重要的是要仔细规划并测试各种场景，以确保系统的稳定性和性能。</p>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[Redis持久化之间的差别]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/redis-chi-jiu-hua-zhi-jian-de-cha-bie"/>
                    <id>tag:https://blog.554321.xyz,2024-09-09:redis-chi-jiu-hua-zhi-jian-de-cha-bie</id>
                    <published>2024-09-09T11:30:58+08:00</published>
                    <updated>2024-09-09T11:30:58+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<p>Redis持久化是为了确保在发生故障或服务重启时，数据不会丢失。作为基于内存的键值存储系统，Redis的高性能主要依赖于将数据存储在内存中，但内存是易失性的，因此在服务器断电或重启时，内存中的数据会丢失。为了解决这个问题，Redis提供了两种主要的持久化方式：RDB（Redis Database）持久化和AOF（Append-Only File）持久化。</p><h3 id="1.-rdb%E6%8C%81%E4%B9%85%E5%8C%96" tabindex="-1">1. RDB持久化</h3><p>RDB持久化是将Redis在某一时刻的内存快照保存到磁盘上。这种方式主要通过执行bgsave命令来实现，它会创建一个子进程来完成数据的持久化，从而避免阻塞主进程。</p><h4 id="%E4%BC%98%E7%82%B9%EF%BC%9A" tabindex="-1">优点：</h4><ul><li>数据恢复快：RDB文件是二进制格式，恢复时速度比AOF快。</li><li>体积小：适合进行数据的备份和灾难恢复。</li><li>对性能影响小：特别是在大数据量的场景下，RDB的生成过程对Redis服务的影响较小。</li></ul><h4 id="%E7%BC%BA%E7%82%B9%EF%BC%9A" tabindex="-1">缺点：</h4><ul><li>数据丢失风险：如果Redis在两次RDB生成之间发生故障，那么这部分数据将会丢失。</li><li>占用内存资源：生成RDB文件时，会创建子进程并复制内存数据，可能会占用较多内存资源。</li></ul><h3 id="2.-aof%E6%8C%81%E4%B9%85%E5%8C%96" tabindex="-1">2. AOF持久化</h3><p>AOF持久化则是将Redis执行的每条写命令记录到AOF文件中，当Redis重启时，可以通过重新执行AOF文件中的命令来恢复数据。</p><h4 id="%E4%BC%98%E7%82%B9%EF%BC%9A-1" tabindex="-1">优点：</h4><ul><li>数据可靠性高：AOF可以最大限度地减少数据丢失，因为它记录了所有的写操作。</li><li>可读性强：AOF文件是纯文本格式，易于阅读和编辑，适合进行数据的修复或恢复。</li></ul><h4 id="%E7%BC%BA%E7%82%B9%EF%BC%9A-1" tabindex="-1">缺点：</h4><ul><li>体积大：随着时间的推移，AOF文件可能会变得非常大，需要定期重写以压缩日志文件。</li><li>对性能有一定影响：在高写入频率的场景下，AOF可能会对Redis的性能产生一定影响。</li></ul><h3 id="3.-%E6%B7%B7%E5%90%88%E6%8C%81%E4%B9%85%E5%8C%96" tabindex="-1">3. 混合持久化</h3><p>在开启混合持久化的情况下，AOF 重写时会把 Redis 的持久化数据，以 RDB 的格式写入到 AOF 文件的开头，之后的数据再以 AOF 的格式化追加的文件的末尾。</p><h4 id="%E4%BC%98%E7%82%B9" tabindex="-1">优点</h4><ul><li>混合持久化结合了 RDB 和 AOF 持久化的优点，开头为 RDB 的格式，使得 Redis 可以更快的启动，同时结合 AOF 的优点，又减低了大量数据丢失的风险。</li></ul><h4 id="%E7%BC%BA%E7%82%B9" tabindex="-1">缺点</h4><ul><li>可读性差：AOF 文件中添加了 RDB 格式的内容，就让 AOF 文件的可读性变得很差。</li><li>兼容性差：如果开启混合持久化，那么此混合持久化 AOF 文件，就不能用在 Redis 4.0 之前版本了。</li></ul><h3 id="%E7%BB%93%E8%AE%BA" tabindex="-1">结论</h3><p>Redis的持久化机制为数据的安全性和可靠性提供了保障。在实际应用中，可以根据具体需求选择合适的持久化方式或同时使用RDB和AOF来确保数据的完整性和可靠性。同时，也需要注意合理配置持久化参数，以平衡数据安全和系统性能之间的关系。</p>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[Mysql中mvcc多版本控制的论述]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/Mysqlmvcc"/>
                    <id>tag:https://blog.554321.xyz,2024-09-06:Mysqlmvcc</id>
                    <published>2024-09-06T17:13:16+08:00</published>
                    <updated>2024-09-06T17:13:16+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h3 id="%E4%B8%80.-%E6%A6%82%E8%BF%B0" tabindex="-1">一. 概述</h3><ul><li>MySQL 的 MVCC（Multi-Version Concurrency Control，多版本并发控制）是一种用来管理数据库读操作和写操作之间冲突的技术，它允许数据库系统在读操作不加锁的情况下，并发地执行写操作。MVCC 主要用于支持高并发的数据库事务处理，特别是在 InnoDB 存储引擎中得到了广泛应用。</li></ul><h3 id="%E4%BA%8C.-mvcc-%E7%9A%84%E4%B8%BB%E8%A6%81%E7%89%B9%E7%82%B9" tabindex="-1">二. MVCC 的主要特点</h3><ul><li>非锁定读：MVCC 允许事务在读取数据时不需要加锁，因此可以显著提高并发性能。</li><li>一致性读：在事务开始时，MVCC 会为该事务创建一个一致性视图（read view），确保该事务只能看到该时间点之前已经提交的数据版本。</li><li>版本控制：MVCC 通过为每个数据行维护多个版本（通过隐藏列和回滚段实现）来实现。每个事务只能看到符合其一致性视图的数据版本。</li></ul><h3 id="%E4%B8%89.-mvcc-%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6" tabindex="-1">三. MVCC 的实现机制</h3><h4 id="3.1.-%E9%9A%90%E8%97%8F%E5%88%97" tabindex="-1">3.1. 隐藏列</h4><ul><li>在 InnoDB 存储引擎中，每行数据都包含三个隐藏列：<br />DB_TRX_ID：记录最后修改该行数据的事务ID。<br />DB_ROLL_PTR：回滚指针，指向该行的undo log记录。<br />DB_ROW_ID：如果没有设置主键，InnoDB会自动生成一个唯一的行ID。</li></ul><h4 id="3.2.-undo-log" tabindex="-1">3.2. Undo Log</h4><ul><li>Undo Log 用于存储数据的旧版本（历史记录），以便在事务回滚时或者为其他事务提供旧版本数据时能够恢复数据。</li></ul><h4 id="3.3.-read-view" tabindex="-1">3.3. Read View</h4><ul><li>当事务开始时，InnoDB 会为该事务创建一个 Read View，该 Read View 记录了当前系统中活跃（未提交）的事务ID列表。通过这个列表，事务可以决定哪些版本的数据对其可见。</li></ul><h3 id="%E5%9B%9B.-mvcc-%E7%9A%84%E8%AF%BB%E6%93%8D%E4%BD%9C" tabindex="-1">四. MVCC 的读操作</h3><ul><li>一致性非锁定读：默认的事务隔离级别（REPEATABLE READ）下，SELECT 语句会采用一致性非锁定读，即只读取在当前事务开始前已经提交的数据版本。</li><li>快照读：与一致性非锁定读类似，都是基于 Read View 来读取数据的。</li></ul><h3 id="%E4%BA%94.-mvcc-%E7%9A%84%E5%86%99%E6%93%8D%E4%BD%9C" tabindex="-1">五. MVCC 的写操作</h3><ul><li>当前读：通过 SELECT … FOR UPDATE 或 SELECT … LOCK IN SHARE MODE 实现的读操作，会锁定读取的数据行，并读取最新的数据版本。</li><li>更新/删除操作：在修改数据时，InnoDB 会将旧版本的数据复制到 undo log 中，并修改数据行中的 DB_TRX_ID 和 DB_ROLL_PTR，以指向新的版本。</li></ul><h3 id="%E5%85%AD.%E6%80%BB%E7%BB%93" tabindex="-1">六.总结</h3><p>MVCC 通过版本控制和 Read View 机制，实现了在不加锁的情况下并发读取数据，同时保证了事务的隔离性和一致性。这是 InnoDB 存储引擎能够支持高并发事务处理的关键技术之一。</p>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[Java中的线程池究竟如何进行配置]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/java-thread-pool"/>
                    <id>tag:https://blog.554321.xyz,2024-09-06:java-thread-pool</id>
                    <published>2024-09-06T16:52:59+08:00</published>
                    <updated>2024-09-06T16:52:59+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<p>Java中的线程池配置是一个涉及多个参数的过程，这些参数共同决定了线程池的行为和性能。以下是对Java线程池配置方法的详细解析：</p><h3 id="%E4%B8%80%E3%80%81%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E4%B8%BB%E8%A6%81%E5%8F%82%E6%95%B0" tabindex="-1">一、线程池的主要参数</h3><h4 id="1.1-corepoolsize%EF%BC%88%E6%A0%B8%E5%BF%83%E7%BA%BF%E7%A8%8B%E6%95%B0%EF%BC%89" tabindex="-1">1.1 corePoolSize（核心线程数）</h4><ul><li>定义了线程池中的核心线程数量。这些线程即使在空闲时也不会被销毁，除非线程池被关闭或设置了allowCoreThreadTimeout为true。</li><li>当新任务提交到线程池时，如果当前线程数小于corePoolSize，则即使有空闲线程，线程池也会创建新线程来处理任务。</li></ul><h4 id="1.2-maximumpoolsize%EF%BC%88%E6%9C%80%E5%A4%A7%E7%BA%BF%E7%A8%8B%E6%95%B0%EF%BC%89" tabindex="-1">1.2 maximumPoolSize（最大线程数）</h4><ul><li>定义了线程池中允许的最大线程数。当线程池中的线程数达到corePoolSize且任务队列已满时，如果还有新的任务提交，线程池会创建新线程（但总数不超过maximumPoolSize）来处理这些任务。</li></ul><h4 id="1.3-keepalivetime%EF%BC%88%E7%BA%BF%E7%A8%8B%E7%A9%BA%E9%97%B2%E6%97%B6%E9%97%B4%EF%BC%89" tabindex="-1">1.3 keepAliveTime（线程空闲时间）</h4><ul><li>当线程池中的线程数量超过corePoolSize时，如果某个线程的空闲时间达到了keepAliveTime，那么这个线程将被终止。</li><li>注意，这个参数仅对非核心线程有效，核心线程即使空闲也不会因为keepAliveTime而终止，除非设置了allowCoreThreadTimeout为true。</li></ul><h4 id="1.4-unit%EF%BC%88%E6%97%B6%E9%97%B4%E5%8D%95%E4%BD%8D%EF%BC%89" tabindex="-1">1.4 unit（时间单位）</h4><ul><li>keepAliveTime参数的时间单位，如秒（TimeUnit.SECONDS）、毫秒（TimeUnit.MILLISECONDS）等。</li></ul><h4 id="1.5-workqueue%EF%BC%88%E4%BB%BB%E5%8A%A1%E9%98%9F%E5%88%97%EF%BC%89" tabindex="-1">1.5 workQueue（任务队列）</h4><ul><li>用于存放待执行的任务。当线程池中的线程数达到corePoolSize时，新任务会被放入队列中等待执行。</li><li>Java提供了多种类型的队列，如ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue等，可以根据实际需求选择合适的队列。</li></ul><h4 id="1.6-threadfactory%EF%BC%88%E7%BA%BF%E7%A8%8B%E5%B7%A5%E5%8E%82%EF%BC%89" tabindex="-1">1.6 threadFactory（线程工厂）</h4><ul><li>用于创建新线程的工厂。通过自定义线程工厂，可以设定新创建线程的优先级、守护线程状态、线程名称等。</li></ul><h4 id="1.7-handler%EF%BC%88%E6%8B%92%E7%BB%9D%E7%AD%96%E7%95%A5%EF%BC%89" tabindex="-1">1.7 handler（拒绝策略）</h4><ul><li>当线程池无法处理新任务时（即线程数达到maximumPoolSize且队列已满），会执行拒绝策略。Java提供了几种内置的拒绝策略，如AbortPolicy（抛出异常）、CallerRunsPolicy（由调用线程处理任务）、DiscardPolicy（丢弃任务）、DiscardOldestPolicy（丢弃队列中最老的任务）等。</li><li>也可以自定义拒绝策略，通过实现RejectedExecutionHandler接口来实现。</li></ul><h3 id="%E4%BA%8C%E3%80%81%E9%85%8D%E7%BD%AE%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E6%AD%A5%E9%AA%A4" tabindex="-1">二、配置线程池的步骤</h3><h4 id="2.1-%E7%A1%AE%E5%AE%9A%E6%A0%B8%E5%BF%83%E7%BA%BF%E7%A8%8B%E6%95%B0%E5%92%8C%E6%9C%80%E5%A4%A7%E7%BA%BF%E7%A8%8B%E6%95%B0" tabindex="-1">2.1 确定核心线程数和最大线程数</h4><ul><li>根据任务的类型和系统的资源情况来确定。对于CPU密集型任务，线程数应设置为CPU核心数或略小于核心数；对于IO密集型任务，线程数可以设置得更大一些，以充分利用IO资源。</li></ul><h4 id="2.2-%E9%80%89%E6%8B%A9%E5%90%88%E9%80%82%E7%9A%84%E4%BB%BB%E5%8A%A1%E9%98%9F%E5%88%97" tabindex="-1">2.2 选择合适的任务队列</h4><ul><li>根据任务的性质和业务需求选择合适的队列。例如，如果希望任务能够立即执行，可以选择SynchronousQueue；如果希望限制任务的并发数，可以选择有界队列如ArrayBlockingQueue。</li></ul><h4 id="2.3-%E8%AE%BE%E7%BD%AE%E7%BA%BF%E7%A8%8B%E7%A9%BA%E9%97%B2%E6%97%B6%E9%97%B4%E5%92%8C%E6%97%B6%E9%97%B4%E5%8D%95%E4%BD%8D" tabindex="-1">2.3 设置线程空闲时间和时间单位</h4><ul><li>根据实际需求设置非核心线程的空闲时间。如果希望线程池能够动态调整线程数，可以设置一个较短的空闲时间；如果希望线程池保持一定的稳定性，可以设置一个较长的空闲时间。</li></ul><h4 id="2.4%EF%BC%88%E5%8F%AF%E9%80%89%EF%BC%89%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BA%BF%E7%A8%8B%E5%B7%A5%E5%8E%82" tabindex="-1">2.4（可选）自定义线程工厂</h4><ul><li>如果需要自定义线程的创建过程，可以通过实现ThreadFactory接口来创建自定义的线程工厂。</li></ul><h4 id="2.5%EF%BC%88%E5%8F%AF%E9%80%89%EF%BC%89%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8B%92%E7%BB%9D%E7%AD%96%E7%95%A5" tabindex="-1">2.5（可选）自定义拒绝策略</h4><ul><li>如果内置的拒绝策略不满足需求，可以通过实现RejectedExecutionHandler接口来创建自定义的拒绝策略。</li></ul><h4 id="2.6-%E5%88%9B%E5%BB%BA%E7%BA%BF%E7%A8%8B%E6%B1%A0" tabindex="-1">2.6 创建线程池</h4><ul><li>使用ThreadPoolExecutor类的构造器来创建线程池，并传入上述配置参数。</li></ul><h3 id="%E4%B8%89%E3%80%81%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81" tabindex="-1">三、示例代码</h3><pre><code class="language-">import java.util.concurrent.ArrayBlockingQueue;  import java.util.concurrent.ThreadPoolExecutor;  import java.util.concurrent.TimeUnit;    public class ThreadPoolConfigExample {      public static void main(String[] args) {          int corePoolSize = 5;          int maximumPoolSize = 10;          long keepAliveTime = 1L;          TimeUnit unit = TimeUnit.MINUTES;          ArrayBlockingQueue&lt;Runnable&gt; workQueue = new ArrayBlockingQueue&lt;&gt;(100);          ThreadPoolExecutor executor = new ThreadPoolExecutor(                  corePoolSize,                  maximumPoolSize,                  keepAliveTime,                  unit,                  workQueue          );            // 提交任务到线程池          // ...            // 关闭线程池          executor.shutdown();      }  }</code></pre><h4 id="%E5%9B%9B%E3%80%81%E7%BB%93%E8%AE%BA" tabindex="-1">四、结论</h4><ul><li>以上的配置和理论都是理想型的，在工作开发当中，线程不宜多也不能少，能够正常的榨干cpu的性能，及时处理任务就可以了</li></ul>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[JVM 如何定位线程阻塞和死锁]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/jvm-ru-he-ding-wei-xian-cheng-zu-sai"/>
                    <id>tag:https://blog.554321.xyz,2024-09-06:jvm-ru-he-ding-wei-xian-cheng-zu-sai</id>
                    <published>2024-09-06T16:04:39+08:00</published>
                    <updated>2024-09-06T16:04:39+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<p>在Java虚拟机（JVM）中，定位线程阻塞是一个常见的调试和性能调优任务。线程阻塞通常发生在多种情况下，如等待I/O操作完成、等待数据库响应、锁竞争等。要有效地定位和解决线程阻塞问题，可以采用以下几种方法：</p><h3 id="1.-%E4%BD%BF%E7%94%A8java%E8%87%AA%E5%B8%A6%E7%9A%84%E7%BA%BF%E7%A8%8B%E8%BD%AC%E5%82%A8%EF%BC%88thread-dump%EF%BC%89" tabindex="-1">1. 使用Java自带的线程转储（Thread Dump）</h3><h4 id="1.1-%E7%BA%BF%E7%A8%8B%E8%BD%AC%E5%82%A8%E7%9A%84%E6%A6%82%E5%BF%B5" tabindex="-1">1.1 线程转储的概念</h4><ul><li>线程转储是诊断Java应用程序中线程阻塞问题的一种有效方式。通过获取JVM的线程转储（Thread Dump），可以了解某一时刻JVM中所有线程的状态，包括它们是否阻塞、等待什么资源、持有哪些锁等。</li></ul><h4 id="1.2-%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E7%BA%BF%E7%A8%8B%E8%BD%AC%E5%82%A8%EF%BC%9A" tabindex="-1">1.2 如何获取线程转储：</h4><ul><li>使用jstack工具：对于基于HotSpot的JVM，可以使用JDK自带的jstack工具来获取当前JVM实例的线程转储。命令格式通常是jstack [option] &lt;pid&gt;，其中&lt;pid&gt;是Java进程的ID。</li><li>使用jcmd工具：jcmd是JDK 7引入的一个新工具，也可以用来生成线程转储，并提供了比jstack更多的功能。命令格式如jcmd &lt;pid&gt; Thread.print。</li><li>通过JVM内建功能：一些JVM实现提供了内建的生成线程转储的功能，如通过JMX或发送特定信号给JVM进程。</li></ul><h3 id="2.-%E5%88%86%E6%9E%90%E7%BA%BF%E7%A8%8B%E8%BD%AC%E5%82%A8" tabindex="-1">2. 分析线程转储</h3><ul><li><p>获取线程转储后，下一步是分析它。在转储中，查找处于BLOCKED、WAITING或TIMED_WAITING状态的线程。这些线程可能正在等待资源（如锁、IO操作完成等）。</p></li><li><p>查看线程状态：确认哪些线程是阻塞的，并关注它们等待的资源。</p></li><li><p>检查锁和同步块：如果线程在尝试获取锁时被阻塞，查看持有该锁的线程的状态和调用栈，以确定是否存在死锁或不必要的锁持有。</p></li><li><p>查看I/O和等待时间：如果线程在等待I/O操作完成，分析相关资源（如数据库、文件、网络）的负载和性能。</p></li><li><p>下图为TDA工具进行进行转储文件分析，它可以把线程分为几组</p><div align="center"> <img src="https://oss.554321.xyz/blog/tda-main-screen.png" width = 600  /> </div></li></ul><h3 id="3.-%E7%BC%96%E5%86%99%E5%92%8C%E8%BF%90%E8%A1%8C%E7%9B%91%E6%8E%A7%E4%BB%A3%E7%A0%81" tabindex="-1">3. 编写和运行监控代码</h3><ul><li>在应用程序中，可以编写一些监控代码来检测潜在的阻塞问题。例如，可以监控锁的获取时间、方法执行时间等，并在超过某个阈值时记录日志或发送警报。</li></ul>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[JVM（Java虚拟机）如何排查内存泄漏]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/JVMJava"/>
                    <id>tag:https://blog.554321.xyz,2024-09-06:JVMJava</id>
                    <published>2024-09-06T15:52:57+08:00</published>
                    <updated>2024-09-06T15:52:57+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h3 id="1.-%E7%90%86%E8%A7%A3%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F" tabindex="-1">1. 理解内存泄漏</h3><ul><li>内存泄漏是指程序在运行时，未能及时释放不再使用的内存空间，导致内存使用量持续增加，最终可能导致OutOfMemoryError错误。在Java中，这通常是由于对象被错误地保持引用，使得垃圾回收器（GC）无法回收这些对象。</li></ul><h3 id="2.%E6%94%B6%E9%9B%86%E5%A0%86%E8%BD%AC%E5%82%A8%E6%96%87%E4%BB%B6" tabindex="-1">2.收集堆转储文件</h3><ul><li>通过设置JVM启动参数-XX:+HeapDumpOnOutOfMemoryError，可以在发生OutOfMemoryError时自动生成堆转储文件。</li><li>使用jmap命令也可以生成堆转储文件，命令格式如jmap -dump:live,format=b,file=&lt;filename&gt; &lt;pid&gt;。</li></ul><h3 id="3.-%E4%BD%BF%E7%94%A8%E5%86%85%E5%AD%98%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7" tabindex="-1">3. 使用内存分析工具</h3><ul><li>VisualVM：这是一个强大的多合一工具，提供了内存监控、线程监控、堆转储分析等功能。</li><li>Eclipse Memory Analyzer (MAT)：MAT是一个快速且功能丰富的Java堆内存分析工具，可以帮助开发者识别内存泄漏和减少内存消耗。</li><li>JProfiler：这是一个商业的Java性能分析工具，提供了深入的内存和CPU性能分析功能。</li></ul><h3 id="4.%E4%B8%8B%E5%9B%BE%E5%B1%95%E7%A4%BAmat%E5%8E%BB%E5%88%86%E6%9E%90%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F" tabindex="-1">4.下图展示MAT去分析内存泄漏</h3><div align=center><p><img src="https://oss.554321.xyz/blog/mat-use.png" alt="mat-use" /></p>]]>
                        
                    </content>
                </entry>
            
                <entry>
                    <title><![CDATA[JVM 的概念、结构、内存模型、常见垃圾收集器等方面的基础知识]]></title>
                    <link rel="alternate" type="text/html"
                          href="/archives/jvm-gai-lian"/>
                    <id>tag:https://blog.554321.xyz,2024-09-06:jvm-gai-lian</id>
                    <published>2024-09-06T00:44:14+08:00</published>
                    <updated>2024-09-06T00:44:14+08:00</updated>
                    <author>
                        <name>青云</name>
                        <uri>https://blog.554321.xyz</uri>
                    </author>
                    <content type="html">
                        
                            <![CDATA[<h1 id="java-%E8%99%9A%E6%8B%9F%E6%9C%BA%EF%BC%88jvm%EF%BC%89%E7%AE%80%E4%BB%8B" tabindex="-1">Java 虚拟机（JVM）简介</h1><p>Java 虚拟机（JVM, Java Virtual Machine）是 Java 程序执行的运行时环境，负责将编译后的字节码解释为机器指令，并进行内存管理和垃圾回收。</p><h2 id="1.-jvm-%E7%BB%93%E6%9E%84" tabindex="-1">1. JVM 结构</h2><p>JVM 的主要组成部分包括以下几个部分：</p><ul><li><strong>类加载器（Class Loader Subsystem）</strong>：负责将 .class 文件加载到内存中。</li><li><strong>运行时数据区（Runtime Data Area）</strong>：JVM 内存模型，包括方法区、堆、栈等。</li><li><strong>执行引擎（Execution Engine）</strong>：将字节码解释执行或编译成本地机器码。</li><li><strong>本地方法接口（Native Interface）</strong>：调用本地（如 C/C++）代码。</li><li><strong>垃圾收集器（Garbage Collector）</strong>：自动管理内存，回收不再使用的对象。</li></ul><h2 id="2.-jvm-%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B" tabindex="-1">2. JVM 内存模型</h2><p>JVM 内存模型分为多个区域，每个区域有不同的作用：</p><h3 id="2.1-%E5%A0%86%EF%BC%88heap%EF%BC%89" tabindex="-1">2.1 堆（Heap）</h3><ul><li>堆是用于存储所有对象实例和数组的内存区域，几乎所有的对象都在这里分配内存。</li><li>堆在 JVM 启动时创建，堆的大小可以通过 <code>-Xms</code>（初始大小）和 <code>-Xmx</code>（最大大小）参数进行控制。</li></ul><p><img src="https://oss.554321.xyz/blog/stack.png" alt="stack" /></p><h3 id="2.2-%E6%A0%88%EF%BC%88stack%EF%BC%89" tabindex="-1">2.2 栈（Stack）</h3><ul><li>每个线程在执行方法时都会创建一个栈帧，存储局部变量、操作数栈、动态链接、方法出口等。</li><li>每个方法调用都会在栈中分配一个栈帧，方法调用结束后栈帧会被销毁。</li></ul><p><img src="https://oss.554321.xyz/blog/heap.png" alt="heap" /></p><h3 id="2.3-%E6%96%B9%E6%B3%95%E5%8C%BA%EF%BC%88method-area%EF%BC%89" tabindex="-1">2.3 方法区（Method Area）</h3><ul><li>存储类结构信息（包括类的元数据、常量、静态变量等）。</li><li>从 JDK 8 开始，方法区的实现变为<strong>元空间（Metaspace）</strong>。</li></ul><p><img src="https://oss.554321.xyz/blog/function-area.png" alt="function-area" /></p><h3 id="2.4-%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8%EF%BC%88program-counter%2C-pc-register%EF%BC%89" tabindex="-1">2.4 程序计数器（Program Counter, PC Register）</h3><ul><li>每个线程都有一个程序计数器，记录当前线程所执行的字节码指令的地址。</li><li>如果是本地方法，程序计数器为空。</li></ul><h2 id="3.-jvm-%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%EF%BC%88garbage-collection%EF%BC%89" tabindex="-1">3. JVM 垃圾回收（Garbage Collection）</h2><p>JVM 提供了自动垃圾回收机制，用于释放不再使用的对象。常见的垃圾收集器包括：</p><h3 id="3.1-parallel-scavenge-gc" tabindex="-1">3.1 Parallel Scavenge GC</h3><ul><li>也是针对新生代的并行多线程收集器，使用复制算法。它关注的是吞吐量（即用户线程运行时间与总时间的比例），并允许用户设置最大垃圾收集停顿时间等参数。</li></ul><h3 id="3.2-cms-gc" tabindex="-1">3.2 CMS GC</h3><ul><li>虽然主要关注于低停顿时间，但它也适用于老年代。CMS GC使用标记-清除算法，并与用户线程并发执行垃圾回收。然而，它会产生内存碎片，并且在某些情况下可能需要使用Full GC来清理这些碎片。</li></ul><h3 id="3.3-g1-gc" tabindex="-1">3.3 G1 GC</h3><ul><li>是一种面向服务端的垃圾收集器，它同时适用于新生代和老年代。G1 GC使用了一种混合的收集算法，即在新生代使用复制算法，在老年代则使用标记-整理算法（但进行了优化以适应分代收集的需求）。G1 GC的目标是同时满足低停顿时间和高吞吐量。</li></ul><h2 id="4.-%E5%B8%B8%E7%94%A8-jvm-%E5%8F%82%E6%95%B0" tabindex="-1">4. 常用 JVM 参数</h2><p>在启动 JVM 时可以使用一些参数来调整其行为：</p><ul><li><code>-Xms&lt;size&gt;</code>：设置 JVM 堆的初始大小。</li><li><code>-Xmx&lt;size&gt;</code>：设置 JVM 堆的最大大小。</li><li><code>-XX:+UseG1GC</code>：启用 G1 垃圾收集器。</li><li><code>-XX:+PrintGCDetails</code>：打印垃圾收集的详细信息。</li></ul><h2 id="5.-jvm-%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B" tabindex="-1">5. JVM 执行流程</h2><ol><li><strong>加载</strong>：类加载器将 .class 文件加载到内存。</li><li><strong>链接</strong>：包括验证、准备和解析阶段。确保类的正确性，分配静态变量。</li><li><strong>初始化</strong>：执行类的静态初始化器或静态块，将静态变量赋值。</li></ol><h2 id="6.-jvm-%E8%B0%83%E4%BC%98" tabindex="-1">6. JVM 调优</h2><h3 id="6.1-%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E8%B0%83%E4%BC%98" tabindex="-1">6.1 垃圾回收调优</h3><ul><li>观察 GC 日志，确保 GC 频率和暂停时间在可接受范围内。</li><li>对于响应时间敏感的应用，可以使用低延迟 GC（如 G1 或 ZGC）。</li><li>调整堆大小，根据应用的内存使用情况选择合适的初始和最大堆大小。</li></ul><h3 id="6.2-%E5%86%85%E5%AD%98%E8%B0%83%E4%BC%98" tabindex="-1">6.2 内存调优</h3><ul><li>如果频繁发生 <code>OutOfMemoryError</code>，可以考虑增加堆大小。</li><li>在使用 Metaspace 时，<code>-XX:MaxMetaspaceSize</code> 可以限制元空间大小。</li></ul>]]>
                        
                    </content>
                </entry>
            
        
    </feed>
