文章列表

这可能是目前最透彻的Netty原理架构解析

作者:微信小助手

<section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件、整体架构,知其然且知其所以然,希望给大家在实际开发实践、学习开源项目方面提供参考。</span></p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> </section> <figure> <p style="line-height: 1.75em;"><br></p> </figure> <section class="" data-mpa-template-id="1120346" data-mpa-color="null" data-mpa-category="fav"> <section data-mpa-template-id="1115154" data-mpa-color="null" data-mpa-category="fav"> <section> <section> <section class="" data-mpa-template-id="1120345" data-mpa-color="null" data-mpa-category="fav"> <section> <section class="" powered-by="xiumi.us"> <section class=""> <section class=""> <section class=""> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.46703296703296704" data-s="300,640" src="/upload/892f9bd0c68eec5385eca2fc91e0b640.png" data-type="png" data-w="910" style=""></p> </section> </section> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></span></p> </section> </section> </section> </section> </section> </section> </section> <section class="" data-mpa-template-id="1120346" data-mpa-color="null" data-mpa-category="fav"> <section data-mpa-template-id="1115154" data-mpa-color="null" data-mpa-category="fav"> <section> <section> <section class="" data-mpa-template-id="1120345" data-mpa-color="null" data-mpa-category="fav"> <section> <section class="" powered-by="xiumi.us"> <section class=""> <p style="line-height: normal;"><br></p> <section class=""> <section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">JDK 原生 NIO 程序的问题</p> </section> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">JDK 原生也有一套网络应用程序 API,但是存在一系列问题,主要如下:</span></p> </section> </section> </section> </section> </section> </section> </section> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">NIO 的类库和 API 繁杂,使用麻烦。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">你需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">需要具备其他的额外技能做铺垫。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如熟悉 Java 多线程编程,因为 NIO 编程涉及到 Reactor 模式,你必须对多线程和网路编程非常熟悉,才能编写出高质量的 NIO 程序。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可靠性能力补齐,开发工作量和难度都非常大。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等等。</span></p><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">NIO 编程的特点是功能开发相对容易,但是可靠性能力补齐工作量和难度都非常大。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">JDK NIO 的 Bug。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如臭名昭著的 Epoll Bug,它会导致 Selector 空轮询,最终导致 CPU 100%。</span></p><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">官方声称在 JDK 1.6 版本的 update 18 修复了该问题,但是直到 JDK 1.7 版本该问题仍旧存在,只不过该 Bug 发生概率降低了一些而已,它并没有被根本解决。</span></p></li> </ul> <section class="" data-mpa-template-id="1120346" data-mpa-color="null" data-mpa-category="fav"> <section data-mpa-template-id="1115154" data-mpa-color="null" data-mpa-category="fav"> <section> <section> <section class="" data-mpa-template-id="1120345" data-mpa-color="null" data-mpa-category="fav"> <section> <section class="" powered-by="xiumi.us"> <section class=""> <p style="line-height: normal;"><br></p> <section class=""> <section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">Netty 的特点</p> </section> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">Netty 对 JDK 自带的 NIO 的 API 进行封装,解决上述问题,主要特点有:</span></p> </section> </section> </section> </section> </section> </section> </section> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">设计优雅,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">适用于各种传输类型的统一 API 阻塞和非阻塞 Socket;基于灵活且可扩展的事件模型,可以清晰地分离关注点;高度可定制的线程模型 - 单线程,一个或多个线程池;真正的无连接数据报套接字支持(自 3.1 起)。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">使用方便</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">,详细记录的 Javadoc,用户指南和示例;没有其他依赖项,JDK 5(Netty 3.x)或 6(Netty 4.x)就足够了。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">高性能,吞吐量更高,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">延迟更低;减少资源消耗;最小化不必要的内存复制。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">安全,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">完整的 SSL/TLS 和 StartTLS 支持。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">社区活跃,不断更新,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">社区活跃,版本迭代周期短,发现的 Bug&nbsp;可以被及时修复,同时,更多的新功能会被加入。</span></p></li> </ul> <section class="" data-mpa-template-id="1120346" data-mpa-color="null" data-mpa-category="fav"> <section data-mpa-template-id="1115154" data-mpa-color="null" data-mpa-category="fav"> <section> <section> <section class="" data-mpa-template-id="1120345" data-mpa-color="null" data-mpa-category="fav"> <section> <section class="" powered-by="xiumi.us"> <section class=""> <p style="line-height: normal;"><br></p> <section class=""> <section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">Netty 常见使用场景</p> </section> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="line-height: 1.6;font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">Netty 常见的使用场景如下:</span></p> </section> </section> </section> </section> </section> </section> </section> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">互联网行业。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在分布式系统中,各个节点之间需要远程服务调用,高性能的 RPC 框架必不可少,Netty 作为异步高性能的通信框架,往往作为基础通信组件被这些 RPC 框架使用。</span></p><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><strong>典型的应用有:</strong>阿里分布式服务框架 Dubbo 的 RPC 框架使用 Dubbo 协议进行节点间通信,Dubbo 协议默认使用 Netty 作为基础通信组件,用于实现各进程节点之间的内部通信。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">游戏行业。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">无论是手游服务端还是大型的网络游戏,Java 语言得到了越来越广泛的应用。Netty 作为高性能的基础通信组件,它本身提供了 TCP/UDP 和 HTTP 协议栈。</span></p><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">非常方便定制和开发私有协议栈,账号登录服务器,地图服务器之间可以方便的通过 Netty 进行高性能的通信。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">大数据领域。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">经典的 Hadoop 的高性能通信和序列化组件 Avro 的 RPC 框架,默认采用 Netty 进行跨界点通信,它的 Netty Service 基于 Netty 框架二次封装实现。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">有兴趣的读者可以了解一下目前有哪些开源项目使用了 Netty:Related Projects。</span></p> <section class="" data-mpa-template-id="1120346" data-mpa-color="null" data-mpa-category="fav"> <section data-mpa-template-id="1115154" data-mpa-color="null" data-mpa-category="fav"> <section> <section> <section class="" data-mpa-template-id="1120345" data-mpa-color="null" data-mpa-category="fav"> <section> <section class="" powered-by="xiumi.us"> <section class=""> <p style="line-height: normal;"><br></p> <section class=""> <section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">Netty 高性能设计</p> </section> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Netty 作为异步事件驱动的网络,高性能之处主要来自于其 I/O 模型和线程处理模型,前者决定如何收发数据,后者决定如何处理数据。<br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>I/O 模型</strong></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用什么样的通道将数据发送给对方,BIO、NIO 或者 AIO,I/O 模型在很大程度上决定了框架的性能。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">阻塞 I/O</span></strong></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">传统阻塞型 I/O(BIO)可以用下图表示:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.7157738095238095" data-s="300,640" src="/upload/e25d77b5875223896eec9875c30cd945.png" data-type="png" data-w="672" style=""></p> <figure> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">Blocking I/O</span></em></span></p> <p style="line-height: normal;"><br></p> </figure> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">特点如下:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每个请求都需要独立的线程完成数据 Read,业务处理,数据 Write 的完整操作</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">问题。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当并发数较大时,需要创建大量线程来处理连接,系统资源占用较大。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费。</span></p></li> </ul> <h3 style="line-height: normal;"><br></h3> <h3 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">I/O 复用模型</span></strong></span></h3> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.533457249070632" data-s="300,640" src="/upload/d3d5c3f4a95c72fa7ac04797312bcaa8.png" data-type="png" data-w="1076" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在 I/O 复用模型中,会用到 Select,这个函数也会使进程阻塞,但是和阻塞 I/O 所不同的是这两个函数可以同时阻塞多个 I/O 操作。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而且可以同时对多个读操作,多个写操作的 I/O 函数进行检测,直到有数据可读或可写时,才真正调用 I/O 操作函数。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Netty 的非阻塞 I/O 的实现关键是基于 I/O 复用模型,这里用 Selector 对象表示:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.9621087314662273" data-s="300,640" src="/upload/b1d9cac167b417f1558b2b4b7eb509a2.png" data-type="png" data-w="607" style=""></p> <figure> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">Nonblocking I/O</span></em></span></p> </figure> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Netty 的 IO 线程 NioEventLoop 由于聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端连接。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当线程从某客户端 Socket 通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 I/O 阻塞导致的线程挂起。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">一个 I/O 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 I/O 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。</span></p> <p style="line-height: normal;"><br></p> <h3 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">基于 Buffer</span></strong></span></h3> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">传统的 I/O 是面向字节流或字符流的,以流式的方式顺序地从一个 Stream 中读取一个或多个字节, 因此也就不能随意改变读取指针的位置。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在 NIO 中,抛弃了传统的 I/O 流,而是引入了 Channel 和 Buffer 的概念。在 NIO 中,只能从 Channel 中读取数据到 Buffer 中或将数据从&nbsp;Buffer 中写入到 Channel。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">基于 Buffer 操作不像传统 IO 的顺序操作,NIO 中可以随意地读取任意位置的数据。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;"> <section class="V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>线程模型</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">数据报如何读取?读取之后的编解码在哪个线程进行,编解码后的消息如何派发,线程模型的不同,对性能的影响也非常大。</span></p> <p style="line-height: normal;"><br></p> <h3 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">事件驱动模型</span></strong></span></h3> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">通常,我们设计一个事件处理模型的程序有两种思路:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">轮询方式,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">线程不断轮询访问相关事件发生源有没有发生事件,有发生事件就调用事件处理逻辑。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事件驱动方式,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">发生事件,主线程把事件放入事件队列,在另外线程不断循环消费事件列表中的事件,调用事件对应的处理逻辑处理事件。事件驱动方式也被称为消息通知方式,其实是设计模式中观察者模式的思路。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">以 GUI 的逻辑处理为例,说明两种逻辑的不同:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">轮询方式,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">线程不断轮询是否发生按钮点击事件,如果发生,调用处理逻辑。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事件驱动方式,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">发生点击事件把事件放入事件队列,在另外线程消费的事件列表中的事件,根据事件类型调用相关事件处理逻辑。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">这里借用 O'Reilly 大神关于事件驱动模型解释图:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.7647849462365591" data-s="300,640" src="/upload/6f7c87dc4718091d1b6a7a992df731e5.png" data-type="png" data-w="744" style=""></p> <figure> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">事件驱动模型</span></em></span></p> </figure> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">主要包括 4 个基本组件:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事件队列(event queue):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">接收事件的入口,存储待处理事件。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">分发器(event mediator):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">将不同的事件分发到不同的业务逻辑单元。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事件通道(event channel):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">分发器与处理器之间的联系渠道。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">事件处理器(event processor):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">实现业务逻辑,处理完成后会发出事件,触发下一步操作。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">可以看出,相对传统轮询模式,事件驱动有如下优点:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可扩展性好,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">分布式的异步架构,事件处理器之间高度解耦,可以方便扩展事件处理逻辑。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">高性能,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">基于队列暂存事件,能方便并行异步处理事件。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <h3 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">Reactor 线程模型</span></strong></span></h3> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Reactor 是反应堆的意思,Reactor 模型是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor 模式也叫 Dispatcher 模式,即 I/O 多了复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术之一。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">Reactor 模型中有 2 个关键组成:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Reactor,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。<span style="letter-spacing: 1px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.6;">它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人。</span></span></p></li> <li><p style="text-align: justify;line-height: 1.75em;margin-bottom: 5px;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Handlers,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。</span></p></li> </ul> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.6357827476038339" data-s="300,640" src="/upload/734efb7cbddcf37a7d5311890006216a.png" data-type="png" data-w="939" style=""></p> <figure> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">Reactor 模型</span></em></span></p> <p style="line-height: normal;"><br></p> </figure> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">取决于 Reactor 的数量和 Hanndler 线程数量的不同,Reactor 模型有 3 个变种:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">单 Reactor 单线程。</span></strong></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">单 Reactor 多线程。</span></strong></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">主从 Reactor 多线程。</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可以这样理解,Reactor 就是一个执行 while (true) { selector.select(); …} 循环的线程,会源源不断的产生新的事件,称作反应堆很贴切。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">篇幅关系,这里不再具体展开 Reactor 特性、优缺点比较,有兴趣的读者可以参考我之前另外一篇文章:<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655818750&amp;idx=1&amp;sn=85f61fa4add73eddba9973c85f8be131&amp;chksm=bd74de298a03573f9d42b5e6769e7ad7ed24a1d3204ac7ec188579dbb180b988d3db7b362639&amp;scene=21#wechat_redirect" target="_blank">《理解高性能网络模型》</a>。</span></p> <p style="line-height: normal;"><br></p> <h3 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">Netty 线程模型</span></strong></span></h3> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Netty 主要基于主从 Reactors 多线程模型(如下图)做了一定的修改,其中主从 Reactor 多线程模型有多个 Reactor:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">MainReactor 负责客户端的连接请求,并将请求转交给 SubReactor。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">SubReactor 负责相应通道的 IO 读写请求。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">非 IO 请求(具体逻辑处理)的任务则会直接写入队列,等待 worker threads 进行处理。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这里引用 Doug Lee 大神的 Reactor 介绍:Scalable IO in Java 里面关于主从 Reactor 多线程模型的图:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.6842105263157895" data-s="300,640" src="/upload/75472558046e8ef25c67b4b6b11e50cc.png" data-type="png" data-w="874" style=""></p> <figure> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 14px;"><em><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">主从 Rreactor 多线程模型</span></em></span></p> <p style="line-height: normal;"><br></p> </figure> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">特别说明的是:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">虽然 Netty 的线程模型基于主从 Reactor 多线程,借用了 MainReactor 和 SubReactor 的结构。</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">但是实际实现上 SubReactor 和 Worker 线程在同一个线程池中:</span></p> <section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs vbscript" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);padding: 0.5em;display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">EventLoopGroup&nbsp;bossGroup&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;NioEventLoopGroup();<br>EventLoopGroup&nbsp;workerGroup&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;NioEventLoopGroup();<br>ServerBootstrap&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">server</span>&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ServerBootstrap();<br><span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">server</span>.group(bossGroup,&nbsp;workerGroup)<br>.channel(NioServerSocketChannel.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">class</span>)</code></pre> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">上面代码中的 bossGroup 和 workerGroup 是 Bootstrap 构造方法中传入的两个对象,这两个 group 均是线程池:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">bossGroup 线程池则只是在 Bind 某个端口后,获得其中一个线程作为 MainReactor,专门处理端口的 Accept 事件,每个端口对应一个 Boss 线程。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">workerGroup 线程池会被各个 SubReactor 和 Worker 线程充分利用。</span></p></li> </ul> <h3 style="line-height: normal;"><br></h3> <h3 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">异步处理</span></strong></span></h3> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际�

Python Pycharm安装使用(一)

作者:じ☆ve宝贝

##安装 首先去下载最新的pycharm 5,进行安装。可以直接在官网下载。 PyCharm 的激活方式: 1,推荐购买正版。 2,可以选择试用,免费试用30天。 3,网上找激活码。 ##配置pycharm 1,点击Create New Project. ![Python安装](/upload/Python1.png "Python安装") 2.pyCharm风格(配色方案)的调整,可以在:【File】-->【Settings】 的 Editor的子选项里进行设置。 比如我这个配色方案,选择的是Dracula(吸血鬼德库拉伯爵),如下图: ![Python安装](/upload/Python2.png "Python安装") 3.显示行号 ![Python显示行号](/upload/Python7.png "Python显示行号") 4.关闭phpstorm的拼写检查 ![typo: In word](/upload/Python8.png "typo: In word") ##Hello Word ![Python项目创建](/upload/Python3.png "Python项目创建") ![Python项目创建](/upload/Python4.png "Python项目创建") ![Python项目创建](/upload/Python5.png "Python项目创建") ####输出 ![Python项目创建](/upload/Python6.png "Python项目创建") ##结束 pycharm的安装和使用,圆满完成。

Java 去除文字中间的空格

作者:じ☆ve宝贝

#### 去掉字符串中的空格 ``` public class Test{ /** * 去掉字符串中的空格 * @param str * @return String */ public static String removeBlank(String str){ StringBuilder sb = new StringBuilder(); char c = ' '; for(int i = 0 ; i < str.length() ; i++){ char ch = str.charAt(i); if(ch != c){ sb.append(ch); } } return sb.toString(); } ```

web.xml配置文件中<async-supported>true</async-supported>报错的解决方案

作者:じ☆ve宝贝

web.xml总是报cvc-complex-type.2.4.a: Invalid content was found starting with element 错误 在eclipse中的web.xml添加: 1、 http://www.springmodules.org/schema/cache/springmodules-cache.xsd 2、http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd 如下面代码: ``` <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://www.springmodules.org/schema/cache/springmodules-cache.xsd http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <!-- Spring MVC --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/cn/studyjava/context/spring-mvc.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app> ```

咱们从头到尾说一次 Java 的垃圾回收

作者:微信小助手

<p><img class="rich_pages" data-backh="383" data-backw="574" data-before-oversubscription-url="/upload/3a04dc24d541fffc3089809c61422a79.jpg" data-copyright="0" data-cropselx1="0" data-cropselx2="574" data-cropsely1="0" data-cropsely2="288" data-ratio="0.6669776119402985" data-s="300,640" src="/upload/3a04dc24d541fffc3089809c61422a79.jpg" data-type="jpeg" data-w="1072" style="font-size: 14px;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;text-align: center;width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;visibility: visible !important;"><br></p> <section class="" powered-by="xiumi.us" style="white-space: normal;max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;line-height: 27.2px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="margin-right: 0em;margin-left: 0em;padding: 0.5em 1em;max-width: 100%;border-style: none;background-color: rgb(235, 235, 235);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: left;line-height: 1.75em;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;">阿里妹导读:之前上学的时候有一个梗,说在食堂里吃饭,吃完把餐盘端走清理的是 C++ 程序员,吃完直接就走的是 Java 程序员。确实,在 Java 的世界里,似乎我们不用对垃圾回收那么的关注。很多初学者不懂 GC,也能写出一个能用甚至还不错的程序或系统。但其实这并不代表 Java 的 GC 就不重要。相反,它是那么的重要和复杂,以至于出了问题,那些初学者除了打开 GC 日志,看着一堆0101的天</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;">文,啥也做不了。</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;">今天,新零售技术事业群的率鸽(花名)就从头到尾,完整地聊一聊 Java 的垃圾回收。</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"></span></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <br> </section> <p><a class="weapp_image_link" data-miniprogram-appid="wx8053ee31f42155ab" data-miniprogram-path="/pages/index/index?url=https://developer.aliyun.com/special/tech-java" data-miniprogram-nickname="ALI开发者" href="" data-miniprogram-type="image" data-miniprogram-servicetype=""><img class="rich_pages" data-ratio="0.2702104097452935" data-s="300,640" src="/upload/a729125208de9a3bfe347cfc357c0076.jpg" data-type="jpeg" data-w="1806" style=""></a></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <br> </section> <section dir="ltr" style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);"><strong><span style="font-size: 15px;">什么是垃圾回收</span></strong></span> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> </section> <p dir="ltr" style="white-space: normal;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。</span> </section> <p style="white-space: normal;"><br></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Java 语言出来之前,大家都在拼命的写 C 或者 C++ 的程序,而此时存在一个很大的矛盾,C++ 等语言创建对象要不断的去开辟空间,不用的时候又需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都在重复的 allocated,然后不停的析构。于是,有人就提出,能不能写一段程序实现这块功能,每次创建,释放控件的时候复用这段代码,而无需重复的书写呢?</span> </section> <p style="white-space: normal;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">1960年,基于 MIT 的 Lisp 首先提出了垃圾回收的概念,而这时 Java 还没有出世呢!所以实际上 GC 并不是Java的专利,GC 的历史远远大于 Java 的历史!</span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <br> </section> <section dir="ltr" style="white-space: normal;text-align: left;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 104, 39);">怎么定义垃圾</span></strong> <br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> </section> <p dir="ltr" style="white-space: normal;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">既然我们要做垃圾回收,首先我们得搞清楚垃圾的定义是什么,哪些内存是需要回收的。</span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"></section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <strong><span style="color: rgb(62, 62, 62);font-size: 15px;">引用计数算法</span></strong> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <strong><span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span></strong> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"></section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">引用计数算法(Reachability Counting)是通过在对象头中分配一个空间来保存该对象被引用的次数(Reference Count)。如果该对象被其它对象引用,则它的引用计数加1,如果删除对该对象的引用,那么它的引用计数就减1,当该对象的引用计数为0时,那么该对象就会被回收。</span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"></section> <pre class="" style="text-align: left;"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer"><span class="code-snippet__built_in">String</span> m = <span class="code-snippet__keyword">new</span> <span class="code-snippet__built_in">String</span>(<span class="code-snippet__string">"jack"</span>);</span></code></pre> </section> <section style="line-height: 1.75em;"> <br> </section></pre> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">先创建一个字符串,这时候"jack"有一个引用,就是 m。</span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="white-space: normal;text-align: center;line-height: 1.75em;"> <img class="" data-ratio="0.35018050541516244" data-type="png" data-w="554" width="300" src="/upload/a03c61f3b902e87fac56f42cfa97aba2.png" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;word-wrap: break-word !important;width: 300px !important;visibility: visible !important;"> <br style="max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;"> </section> <p style="white-space: normal;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">然后将 m 设置为 null,这时候"jack"的引用次数就等于0了,在引用计数算法中,意味着这块内容就需要被回收了。</span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"></section> <pre class="" style="text-align: left;"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> </ul> <pre class="code-snippet__js" data-lang="ini"><code><span class="code-snippet_outer"><span class="code-snippet__attr">m</span> = null;</span></code></pre> </section> <section style="line-height: 1.75em;"> <br> </section></pre> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <img class="" data-ratio="0.2753303964757709" data-type="png" data-w="908" width="500" src="/upload/3baab151fdba316b342e49da6ef6ab53.png" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;word-wrap: break-word !important;width: 500px !important;visibility: visible !important;"> <br style="max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;"> </section> <p style="white-space: normal;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">引用计数算法是将垃圾回收分摊到整个应用程序的运行当中了,而不是在进行垃圾收集时,要挂起整个应用的运行,直到对堆中所有对象的处理都结束。因此,采用引用计数的垃圾收集不属于严格意义上的"Stop-The-World"的垃圾收集机制。</span> </section> <p style="white-space: normal;"><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">看似很美好,但我们知道JVM的垃圾回收就是"Stop-The-World"的,那是什么原因导致我们最终放弃了引用计数算法呢?看下面的例子。</span> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <br> </section> <pre class="" style="text-align: left;"> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">class</span> <span class="code-snippet__title">ReferenceCountingGC</span> {</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">public</span> Object instance;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__title">ReferenceCountingGC</span>(<span class="code-snippet__params">String name</span>)</span>{}</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">static</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">testGC</span>(<span class="code-snippet__params"></span>)</span>{</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> ReferenceCountingGC a = <span class="code-snippet__keyword">new</span> ReferenceCountingGC(<span class="code-snippet__string">"objA"</span>);</span></code><code><span class="code-snippet_outer"> ReferenceCountingGC b = <span class="code-snippet__keyword">new</span> ReferenceCountingGC(<span class="code-snippet__string">"objB"</span>);</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> a.instance = b;</span></code><code><span class="code-snippet_outer"> b.instance = a;</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> a = <span class="code-snippet__literal">null</span>;</span></code><code><span class="code-snippet_outer"> b = <span class="code-snippet__literal">null</span>;</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section style="line-height: 1.75em;"> <br> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section></pre> <section class="" data-style-type="6" data-tools="新媒体排版" data-id="9166" style="white-space: normal;"> <section class="" data-source="bj.96weixin.com"> <section> <section data-css="background-color: rgb(239, 239, 239);box-sizing: border-box;margin-top: -4px;padding: 10px"> <section> <section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">1. 定义2个对象</span> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">2. 相互引用</span> <br style="max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">3. 置空各自的声明引用</span> </section> <section style="text-align: left;line-height: 1.75em;"></section> </section> </section> </section> </section> </section> </section> <section style="white-space: normal;text-align: center;line-height: 1.75em;"> <br> </section> <section style="white-space: normal;text-align: center;line-height: 1.75em;"> <img class="" data-ratio="0.28825622775800713" data-type="png" data-w="2248" title="image.png" src="/upload/b833049b91dd51431fe44ace0d3bd13d.png" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;top: 0px;left: 0px;right: 0px;bottom: 0px;word-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> <br style="max-width: 100%;box-sizing: border-box;word-wrap: break-word !important;"> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <br> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">我们可以看到,最后这2个对象已经不可能再被访问了,但由于他们相互引用着对方,导致它们的引用计数永远都不会为0,通过引用计数算法,也就永远无法通知GC收集器回收它们。</span> </section> <p style="white-space: normal;"><br></p> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">可达性分析算法</span></strong> </section> <section style="white-space: normal;text-align: left;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></strong> </section> <section style="white-sp

eclipse 开发项目必要设置(一)

作者:じ☆ve宝贝

### 设置编码: Window -> Preferences —> General —> Content Types —> Text —> Java Source File 下面的 Default encoding设置为UTF-8 点击Update Window -> Preferences —> General —> Workspace 中Text File encoding 选择other下拉框中选择UTF-8 Window -> Preferences —> Web —> JSP Files 中Encoding 下拉框中选择UTF-8 ### 注释代码格式化: Window -> Preferences —> Java —> Code Style —> Code Templates —> Improt 选择 —> 我的codetemplates.xml ### 代码格式化: Window -> Preferences —> Java —> Code Style —> Formatter 选择 —> java.code.style.xml ### 设置html/jsp文件的自动格式化配置: Window -> Preferences-> Web -> HTML Files-> Editor 中Line width加个0以后保存。 ### 设置XML文件的自动格式化配置: Window -> Preferences -> XML -> XML Files -> Editor : ### 通用配置的解释 设置每行宽度 Line width 设定为80到100个字符。 标签的每个属性都单独一行显示: 选中Split multiple attributes each on a new line 标签结束符不单独占用一行: 不选中Align final bracket in multi-line element tags 去掉所有空行: 选中Clear all blank lines 在标签结束符前添加空格: 选中Insert whitespace before closing empty end-tags 缩进使用空格代替tab: 选中Indent using spaces 设定缩进宽度 Indentation size 设定为4,即缩进4个空格。

PyCharm 启动Django

作者:じ☆ve宝贝

由于Django工程的运行是这样的: ``` $ python3 ./manage.py runserver ``` 所以这里要对其进行配置。 选择菜单 [Run] --> [Edit Configurations...] 弹出如下对话框。 点左上角的 + 号,添加一个Debug配置,并如下配置 ![pycharm启动django](/upload/pycharm_django.png "pycharm启动django")

Codelf 搜索开源代码帮程序员命名

作者:じ☆ve宝贝

Codelf 由前网易前端工程师知名移动前端调试工具MIHTool的作者基于searchcode和有道词典开发完成。目前开源在Github上。 Codelf: http://unbug.github.io/codelf/ Codelf 的 github repo: https://github.com/unbug/codelf

Redis为什么这么快?一文深入了解Redis内存模型!

作者:微信小助手

<section style="box-sizing: border-box;background-color: rgb(255, 255, 255);"> <section class="Powered-by-XIUMI V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section class="" style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section class="" style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;" class=""> <section style="box-sizing: border-box;"> “ </section></span> <section class="" style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">Redis 是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说 Redis 是实现网站高并发不可或缺的一部分。</span></p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> </section> <p style="line-height: 1.75em;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="" data-copyright="0" data-ratio="0.58" data-s="300,640" src="/upload/67bc9d0f43332b4d0f291b70d7496f95.png" data-type="png" data-w="700" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们使用 Redis 时,会接触 Redis 的 5 种对象类型(字符串、哈希、列表、集合、有序集合),丰富的类型是 Redis 相对于 Memcached 等的一大优势。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">在了解 Redis 的 5 种对象类型的用法和特点的基础上,进一步了解 Redis 的内存模型,对 Redis 的使用有很大帮助,例如:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">估算 Redis 内存使用量。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">目前为止,内存的使用成本仍然相对较高,使用内存不能无所顾忌;根据需求合理的评估 Redis 的内存使用量,选择合适的机器配置,可以在满足需求的情况下节约成本。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">优化内存占用。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">了解 Redis 内存模型可以选择更合适的数据类型和编码,更好的利用 Redis 内存。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">分析解决问题。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当 Redis 出现阻塞、内存占用等问题时,尽快发现导致问题的原因,便于分析解决问题。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这篇文章主要介绍 Redis 的内存模型(以 3.0 为例),包括 Redis 占用内存的情况及如何查询、不同的对象类型在内存中的编码方式、内存分配器(jemalloc)、简单动态字符串(SDS)、RedisObject 等;然后在此基础上介绍几个 Redis 内存模型的应用。</span></p> <p style="line-height: normal;"><br></p> <h1 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span></h1> <section style="box-sizing: border-box;background-color: rgb(255, 255, 255);"> <section class="Powered-by-XIUMI V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section class="" style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section class="" style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">Redis 内存统计</p> </section> </section> </section> </section> <p style="line-height: normal;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">工欲善其事必先利其器,在说明 Redis 内存之前首先说明如何统计 Redis 使用内存的情况。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 10px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在客户端通过 redis-cli 连接服务器后(后面如无特殊说明,客户端一律使用redis-cli),通过 info 命令可以查看内存使用情况:info memory。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img data-ratio="0.5907473309608541" src="/upload/fc2d97fa85d78948616b553e131c6146.null" data-type="png" data-w="281" style="border-width: 0px;white-space: normal;max-width: 700px;width: auto !important;visibility: visible !important;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">其中,info 命令可以显示 Redis 服务器的许多信息,包括服务器基本信息、CPU、内存、持久化、客户端连接信息等等;Memory 是参数,表示只显示内存相关的信息。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">返回结果中比较重要的几个说明如下:</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span></p> <section style="box-sizing: border-box;background-color: rgb(255, 255, 255);"> <section class="Powered-by-XIUMI V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section class="" style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section class="" style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </section> <section class="" style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>used_memory</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Redis 分配器分配的内存总量(单位是字节),包括使用的虚拟内存(即 swap);Redis 分配器后面会介绍。used_memory_human 只是显示更友好。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span></p> <section style="box-sizing: border-box;background-color: rgb(255, 255, 255);"> <section class="Powered-by-XIUMI V5" style="box-sizing: border-box;" powered-by="xiumi.us"> <section class="" style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section class="" style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><

关于前端埋点统计方案思考

作者:微信小助手

<p style="margin-bottom: 5px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);font-size: 16px;widows: 1;text-size-adjust: auto;text-align: center;line-height: normal;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击上方</span><span style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(51, 51, 51);box-sizing: border-box !important;overflow-wrap: break-word !important;">“</span><span style="max-width: 100%;color: rgb(0, 82, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">IT平头哥联盟</span></span><span style="max-width: 100%;color: rgb(51, 51, 51);box-sizing: border-box !important;overflow-wrap: break-word !important;">”,</span></span><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">选择“</span></span><span style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;color: rgb(255, 41, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;">置顶或者星标</span><span style="max-width: 100%;font-size: 12px;color: rgb(136, 136, 136);font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">”<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;widows: 1;font-size: 14px;text-size-adjust: auto;letter-spacing: 1px;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box;text-align: center;overflow-wrap: break-word !important;"> <h1 style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;letter-spacing: 0.544px;line-height: normal;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;">与你一起成长~</span></h1> </section> </section> </section> <p><br></p> <p style="margin-bottom: 20px;padding-left: 10px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px 0px 0px 2px;border-top-style: initial;border-right-style: initial;border-bottom-style: initial;border-left-style: solid;border-top-color: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: rgb(221, 221, 221);font-size: 14px;white-space: pre-wrap;word-break: break-all;hyphens: auto;color: rgb(153, 153, 153);font-family: Optima-Regular, PingFangTC-light;line-height: normal;box-sizing: border-box !important;"><span style="font-size: 12px;">本文转载自掘金专栏,作者 呆恋小喵 </span></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">埋点即监控用户在应用表现层的行为,于产品迭代而言至关重要。埋点数据分析是产品需求的 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源</strong>,检验功能是否达预期的 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">佐证</strong>。前端较服务端更接近用户,本小白将在此对前端埋点统计方案述说一二。</span></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">采集埋点数据可做如下分析(以百度统计为例):</span></p> <p style="margin: 15px auto;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;text-align: center;white-space: pre-wrap;word-break: break-all;hyphens: auto;overflow: hidden;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><img class="" data-ratio="3.5945017182130585" src="/upload/4e179aae8cc167caf061f11c17e4ad3a.other" data-type="other" data-w="291" style="border-width: 0px;border-style: initial;border-color: initial;vertical-align: middle;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 291px !important;visibility: visible !important;"></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">将 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">用户属性</strong>、<strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">用户行为</strong> 转化各类可视化图表:</span></p> <p style="margin: 15px auto;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;text-align: center;white-space: pre-wrap;word-break: break-all;hyphens: auto;overflow: hidden;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><img class="" data-ratio="0.18359375" src="/upload/f7730ef0a8ef545b172328d7487eda0.other" data-type="other" data-w="1280" style="background-color: rgb(238, 237, 235);border-width: 0px;border-style: initial;border-color: initial;background-size: 22px;background-position: center center;background-repeat: no-repeat;vertical-align: middle;height: 124.293px !important;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;"></p> <p style="margin: 15px auto;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;text-align: center;white-space: pre-wrap;word-break: break-all;hyphens: auto;overflow: hidden;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><img class="" data-ratio="0.24977777777777777" src="/upload/4f157ac203b3717070195a8c8b2b5e7d.other" data-type="other" data-w="1125" style="background-color: rgb(238, 237, 235);border-width: 0px;border-style: initial;border-color: initial;background-size: 22px;background-position: center center;background-repeat: no-repeat;vertical-align: middle;height: 169.1px !important;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;"></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">不同产品对数据的关注角度不同,可按需采集。如信息流产品对停留时长的关注度更高(统计页面访问 &amp; 跳出时间),商城类较注重“复购率”(统计新老用户),广告类更追求最大限度。</span></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">埋点统计通常分两类:</span></p> <ul class=" list-paddingleft-2" style=""> <li><p style="max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">页面访问量统计</span></p></li> <li><p style="max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">功能点击量统计</span></p><p style="max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.9;white-space: pre-wrap;word-break: break-all;hyphens: auto;box-sizing: border-box !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p></li> </ul> <h3 style="margin-top: 20px;margin-bottom: 20px;padding-left: 25px;font-weight: bold;max-width: 100%;overflow-wrap: break-word;letter-spacing: 0.544px;white-space: normal;border-width: 0px;border-style: initial;border-color: initial;word-break: break-all;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/MpGQUHiaib4ib6j9X9s2kibfaicBLmIm6dUBqor8qjBj66mDs0V98xzicMIaHT0lv8c30WsIR3MNHeCGz091kCp7CqVg/640?wx_fmt=png&quot;);background-position: 0px 8px;background-size: 20px 16px;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(100, 159, 12);line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">页面访问量统计</span></h3> <p style="margin-top: 8px;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">页面访问量统计通常分两类:</span></p> <ul class=" list-paddingleft-2" style=""> <li><p style="max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;"><strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">PV</strong>:页面访问人次</span></p></li> <li><p style="max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;"><strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">UV</strong>:页面访问人数</span></p><p style="max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.9;white-space: pre-wrap;word-break: break-all;hyphens: auto;box-sizing: border-box !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p></li> </ul> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">页面访问量,并非仅仅取决于其内容吸引力,影响因素包含入口 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">外观</strong>、<strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">位置</strong>、<strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">深度</strong> 等等(在此不考虑刚需)。入口外观属 UI 设计范畴,入口位置可通过分析用户点击热力图调整,入口深度可通过分析用户访问路径调整。</span></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">用户点击 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">热力图</strong> 形如:</span></p> <p style="margin: 15px auto;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;text-align: center;white-space: pre-wrap;word-break: break-all;hyphens: auto;overflow: hidden;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><img class="" data-ratio="0.4913194444444444" src="/upload/a8b7a4e649277ef409e4169281013f82.other" data-type="other" data-w="576" style="border-width: 0px;border-style: initial;border-color: initial;vertical-align: middle;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 576px !important;visibility: visible !important;"></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">将核心页面入口置于热力图红色区域?</span></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">采集页面加载 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">from</strong>、<strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">to</strong> 以获知用户访问路径:</span></p> <p style="margin: 15px auto;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;text-align: center;white-space: pre-wrap;word-break: break-all;hyphens: auto;overflow: hidden;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><img class="" data-ratio="0.8771626297577855" src="/upload/93b4e2050c5bef8a4a6db8ac027b21b4.other" data-type="other" data-w="578" style="background-color: rgb(238, 237, 235);border-width: 0px;border-style: initial;border-color: initial;background-size: 22px;background-position: center center;background-repeat: no-repeat;vertical-align: middle;height: 507px !important;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 578px !important;"></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">分析可知用户普遍 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">访问深度</strong>、每一深度 &amp; 每一页面的 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">流失率</strong> 等,依照结果调整核心页面入口源、入口深度?</span></p> <p style="margin-top: 1.8em;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">页面访问量,也并非仅仅取决于产品设计。假若 PV 稳定的页面访问量 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">爆跌</strong>,便需考虑其加载成功率了(或许是枚技术 bug)。</span></p> <h3 style="margin-top: 20px;margin-bottom: 20px;padding-left: 25px;font-weight: bold;max-width: 100%;overflow-wrap: break-word;letter-spacing: 0.544px;white-space: normal;border-width: 0px;border-style: initial;border-color: initial;word-break: break-all;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/MpGQUHiaib4ib6j9X9s2kibfaicBLmIm6dUBqor8qjBj66mDs0V98xzicMIaHT0lv8c30WsIR3MNHeCGz091kCp7CqVg/640?wx_fmt=png&quot;);background-position: 0px 8px;background-size: 20px 16px;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(100, 159, 12);line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">前端如何实现全局 PV 统计,以 Vue 应用为例。</span></h3> <h4 style="margin-top: 8px;margin-bottom: 5px;font-weight: bold;max-width: 100%;overflow-wrap: break-word;letter-spacing: 0.544px;white-space: normal;border-width: 0px;border-style: initial;border-color: initial;word-break: break-all;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">方案一</span></h4> <p style="margin-top: 8px;margin-bottom: 1.8em;max-width: 100%;overflow-wrap: break-word;min-height: 1em;letter-spacing: 0.544px;border-width: 0px;border-style: initial;border-color: initial;font-size: 15px;white-space: pre-wrap;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;"><span style="font-size: 15px;">通过在入口文件 index.js 全局定义 <strong style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">Router.beforeEach</strong>:</span></p> <blockquote class="" style="padding-left: 0px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;letter-spacing: 0.544px;white-space: normal;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre class="" style="margin-top: 0px;margin-bottom: 0px;padding: 1em;max-width: 100%;overflow-wrap: normal;border-width: 0px;border-style: initial;border-color: initial;overflow: auto;background-color: rgb(45, 45, 45);color: rgb(204, 204, 204);font-family: Consolas, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace;word-spacing: normal;word-break: normal;line-height: 1.5;tab-size: 4;hyphens: none;box-sizing: border-box !important;"><p style="margin-top: 3px;margin-bottom: 3px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;font-size: 12px;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;white-space: nowrap !important;"><span style="font-size: 15px;"><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(204, 153, 205);box-sizing: border-box !important;overflow-wrap: break-word !important;">import</span>&nbsp;App&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(204, 153, 205);box-sizing: border-box !important;overflow-wrap: break-word !important;">from</span>&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(126, 198, 153);box-sizing: border-box !important;overflow-wrap: break-word !important;">'./app'</span></span></p><p style="margin-top: 3px;margin-bottom: 3px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;font-size: 12px;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;white-space: nowrap !important;"><span style="font-size: 15px;"><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(204, 153, 205);box-sizing: border-box !important;overflow-wrap: break-word !important;">import</span>&nbsp;Router&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(204, 153, 205);box-sizing: border-box !important;overflow-wrap: break-word !important;">from</span>&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(126, 198, 153);box-sizing: border-box !important;overflow-wrap: break-word !important;">'./router'</span></span></p><p class="" style="margin-top: 3px;margin-bottom: 3px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;line-height: 0;font-size: 12px;word-break: break-all;hyphens: auto;height: 6px;box-sizing: border-box !important;white-space: nowrap !important;"><br style="max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p><p style="margin-top: 3px;margin-bottom: 3px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;font-size: 12px;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;white-space: nowrap !important;"><span style="font-size: 15px;">Router<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(240, 141, 73);box-sizing: border-box !important;overflow-wrap: break-word !important;">beforeEach</span><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">((</span>to<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">,</span>&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(204, 153, 205);box-sizing: border-box !important;overflow-wrap: break-word !important;">from</span><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">,</span>&nbsp;next<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span>&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(103, 205, 204);box-sizing: border-box !important;overflow-wrap: break-word !important;">=&gt;</span>&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">{</span></span></p><p style="margin-top: 3px;margin-bottom: 3px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;font-size: 12px;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;white-space: nowrap !important;"><span style="font-size: 15px;">&nbsp;&nbsp;&nbsp;&nbsp;App<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(240, 141, 73);box-sizing: border-box !important;overflow-wrap: break-word !important;">logEvent</span><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">({</span></span></p><p style="margin-top: 3px;margin-bottom: 3px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;font-size: 12px;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;white-space: nowrap !important;"><span style="font-size: 15px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span>&nbsp;<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;color: rgb(126, 198, 153);box-sizing: border-box !important;overflow-wrap: break-word !important;">'visit'</span><span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">,</span></span></p><p style="margin-top: 3px;margin-bottom: 3px;max-width: 100%;overflow-wrap: break-word;min-height: 1em;border-width: 0px;border-style: initial;border-color: initial;font-size: 12px;word-break: break-all;hyphens: auto;line-height: 2em;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;white-space: nowrap !important;"><span style="font-size: 15px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border-color: initial;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span>&nbsp;to<span class="" style="font-size: 15px;max-width: 100%;border-width: 0px;border-style: initial;border