首页 文章 精选 留言 我的

精选列表

搜索[超融合软件],共10000篇文章
优秀的个人博客,低调大师

国产超好用的规则引擎框架

LiteFlow介绍 LiteFlow是一个开源编排式规则引擎,能够让你的系统逻辑任意编排,可选用脚本书写逻辑,支持多达5种脚本语言,支持丰富的第三方存储的支持,所有的逻辑和规则均可热变更。设计系统和重构系统的神器。 LiteFlow是国内优秀的社区驱动型开源项目,开源2年多,目前已经被各大公司应用在核心系统上。特性以及支持度都非常好。 如果你是第一次知道这个项目,可以去官网或相关的主页进行了解: 项目官网: https://liteflow.yomahub.com gitee托管仓库: https://gitee.com/dromara/liteFlow github托管仓库: https://github.com/dromara/liteflow v2.10.2介绍 我们为每个迭代版本都定了一个版本特性。 LiteFlow 2.10.2的版本特性就是与或非表达式。 除此之外,我们还增强了一些内容,修复了社区提出的bug。一共5个issue,作为此次小版本迭代的组成部分。 与或非表达式 社区里一直有人反应,条件编排能否在EL上写表达式,例如a==5 && b>0这种。 其实编排EL语法一切的操作对象都是组件,所以EL编排语法不能像逻辑代码一样来写很多逻辑过程。 我一直建议逻辑过程,通过java代码或者脚本组件来完成。而脚本组件是可以热更新热替换的。更加灵活。 但是在实际应用中,的确有人需要在条件编排里判断多个条件,而每个条件又是互相独立的组件。那么按照以前的写法,你只能把多个条件的逻辑塞到一个组件里,返回统一的true或者false。 这次我们新增了组件编排层面的与或非表达式,就是AND,OR,NOT表达式。 用法为方法模式:AND(a, b, c)。 可能有些社区里的同学会问,为什么不设计成a && b && c呢,或者是a AND b AND c呢。 我来解释一下,首先这种用法模式和之前的语法呼应,都是方法模式,其次操作符的模式就有点像逻辑了,而这里突出的是编排。再者操作符的模式的几个关键字都被底层占用了。 综上所述,所以延续了之前的EL表述方式。 具体文档在官网EL规则语法大章的与或非表达式小章中。 脚本新增了一些元数据 脚本中现在也可以拿到循环下标了,在元数据里加入了loopIndex和loopObject2个属性。 可以通过_meta.loopIndex和_meta.loopObject来获取到。 所有的脚本元数据可以参照官网的脚本组件大章中的与Java进行交互小章节。 选择表达式的增强和一些bug的修复 现在在选择编排语法上,之前tag属性只能添加到组件上,现在对任何的表达式后面都可以添加tag属性了。 在选择节点的返回上,更加灵活了。 具体见官网的常规组件大章中的选择组件小章节。 此次我们还另外修复了2个bug。 完整更新列表 特性 #I6RF8Y EL表达式里支持并或非操作符 https://gitee.com/dromara/liteFlow/issues/I6RF8Y 增强 #I6QOFJ groovy无法支持#循环下标获取获取,希望脚本可以支持获取循环下标 https://gitee.com/dromara/liteFlow/issues/I6QOFJ 增强 #I6RFOE LiteFlow能否在流程(表达式)添加类似tag字段的属性,提高选择组件的复用率呢? https://gitee.com/dromara/liteFlow/issues/I6RFOE 修复 #I6TRT2 EL表达式里的//被过滤掉了 https://gitee.com/dromara/liteFlow/issues/I6TRT2 修复 #I6URNQ 在CATCH表达中写单独的组件,SLOT中会拿不到异常 https://gitee.com/dromara/liteFlow/issues/I6URNQ 支持和赞助LiteFlow 开源一个项目并坚持2年并不容易,所以我也需要一点赞助来给自己充能,如果各位对LiteFlow这个项目有信心并且愿意支持我的的话,可以在官网首先点击给LiteFlow发电按钮。 但不管你是否选择赞助,我仍然会在社区里尽可能的解决你们的问题。 如何加群 LiteFlow的社区群已经有大约2500人以上了。你有任何问题,都可以在群里问。 关于加群的方式,请参考:https://liteflow.yomahub.com/pages/73c2c3/

优秀的个人博客,低调大师

NuGet 下载超 700万,.NET 框架 Furion v4.8.7.17 发布

这一个月内 Furion 解决了 12 个 Bug~,新增了 16 项特性,调整了 5 处代码,关闭了 113 个 Issues,框架越来越完善,越来越稳定。 2023 年 03 月 15 日,Furion在NuGet平台突破700万下载量。https://www.nuget.org/profiles/monk.soul 0-100万,用时 12个月 100-200万,用时 10个月 200-300万,用时 3个月 300-400万,用时 2个月 400-500万,用时 1个月 500-600万,用时 2个月 600-700万,用时 1个月 查看完整发展事记:https://furion.baiqian.ltd/docs/course 项目信息 Gitee:https://gitee.com/dotnetchina/Furion Github:https://github.com/MonkSoul/Furion 文档:https://dotnetchina.gitee.io/furion 本期亮点 1. 日志输出改进,支持配置日志输出所在程序集、类型和方法签名 旧版本 info: 2023-03-17 18:25:06.7988349 +08:00 星期五 L System.Logging.EventBusService[0] #1 EventBus hosted service is running. info: 2023-03-17 18:25:08.1393952 +08:00 星期五 L Microsoft.Hosting.Lifetime[14] #1 Now listening on: https://localhost:5001 info: 2023-03-17 18:25:08.1620391 +08:00 星期五 L Microsoft.Hosting.Lifetime[14] #1 Now listening on: http://localhost:5000 info: 2023-03-17 18:25:08.1972456 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1 Application started. Press Ctrl+C to shut down. info: 2023-03-17 18:25:08.2456579 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1 Hosting environment: Development info: 2023-03-17 18:25:08.2746134 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1 Content root path: D:\Workplaces\OpenSources\Furion\samples\Furion.Web.Entry info: 2023-03-17 18:25:18.1917784 +08:00 星期五 L Furion.Application.TestLoggerServices[0] #16 我是一个日志 20 新版本 info: 2023-03-17 18:25:06.7988349 +08:00 星期五 L System.Logging.EventBusService[0] #1 [Furion.dll] async Task Furion.EventBus.EventBusHostedService.ExecuteAsync(CancellationToken stoppingToken) EventBus hosted service is running. info: 2023-03-17 18:25:08.1393952 +08:00 星期五 L Microsoft.Hosting.Lifetime[14] #1 [System.Private.CoreLib.dll] void System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<TStateMachine>(ref TStateMachine stateMachine) Now listening on: https://localhost:5001 info: 2023-03-17 18:25:08.1620391 +08:00 星期五 L Microsoft.Hosting.Lifetime[14] #1 [System.Private.CoreLib.dll] void System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<TStateMachine>(ref TStateMachine stateMachine) Now listening on: http://localhost:5000 info: 2023-03-17 18:25:08.1972456 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1 [Microsoft.Extensions.Hosting.dll] void Microsoft.Extensions.Hosting.Internal.ConsoleLifetime.OnApplicationStarted() Application started. Press Ctrl+C to shut down. info: 2023-03-17 18:25:08.2456579 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1 [Microsoft.Extensions.Hosting.dll] void Microsoft.Extensions.Hosting.Internal.ConsoleLifetime.OnApplicationStarted() Hosting environment: Development info: 2023-03-17 18:25:08.2746134 +08:00 星期五 L Microsoft.Hosting.Lifetime[0] #1 [System.Private.CoreLib.dll] void System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(bool throwOnFirstException) Content root path: D:\Workplaces\OpenSources\Furion\samples\Furion.Web.Entry info: 2023-03-17 18:25:18.1917784 +08:00 星期五 L Furion.Application.TestLoggerServices[0] #16 [Furion.Application.dll] void Furion.Application.TestLoggerServices.测试日志() 我是一个日志 20 本期更新 新特性 [新增]Crontab.IsValid(...)静态方法,判断Cron表达式是否有效4.8.7.17⏱️2023.03.20#I6OHO4 [新增]日志配置WithStackFrame,可控制是否输出产生日志的程序集,类型和具体方法4.8.7.16⏱️2023.03.195ad6ae2 [新增] 定时任务看板UI作业列表最近执行时间列和优化显示效果4.8.7.12⏱️2023.03.1526462a8cb5dd17 [新增] 定时任务作业计划/工厂立即执行RunJob方法4.8.7.11⏱️2023.03.15#I6LD9X [新增] 定时任务看板UI提供立即执行功能4.8.7.11⏱️2023.03.15#I6LD9X [新增] 远程请求HttpRequestMessage拓展方法AppendHeaders4.8.7.10⏱️2023.03.14#I6MVHT [新增] 定时任务作业执行上下文JobExecutionContext服务提供器ServiceProvider属性4.8.7.10⏱️2023.03.1402586f8 [新增]定时任务HTTP作业,支持定时请求互联网URL地址4.8.7.7⏱️2023.03.1101d4466 [新增]定时任务作业触发器Trigger执行结果Result和执行耗时ElapsedTime属性4.8.7.7⏱️2023.03.1101d4466 [新增]定时任务作业看板支持查看作业触发器执行结果Result和执行耗时ElapsedTime属性4.8.7.7⏱️2023.03.1101d4466 [新增] 定时任务休眠时长和唤醒时机日志输出4.8.7.6⏱️2023.03.08#I6LANE [新增]Sql高级拦截支持返回IEnumerable<T>和T[]类型值4.8.7.5⏱️2023.03.07f2ca2d3 [新增].m3u8和.ts文件类型MIME支持4.8.7.5⏱️2023.03.07#I6KKEM [新增] 审计日志LoggingMonitor支持对参数贴[SuppressMonitor]特性跳过记录4.8.7.3⏱️2023.03.01#I6IVGW [新增] 审计日志LoggingMonitor监听TraceId、ThreadId、Accept-Language4.8.7.1⏱️2023.02.27df35201 [新增] 规范化结果UnifyContext.GetSerializerSettings(string)静态方法4.8.7.1⏱️2023.02.27#I6HM7T 突破性变化 [调整]定时任务动态作业DynamicJob委托/方法签名4.8.7.10⏱️2023.03.146d56b53 [升级]适配.NET8 Preview.14.8.7⏱️2023.02.22 [升级]脚手架支持创建.NET8 Preview.1项目4.8.7⏱️2023.02.22 问题修复 [修复] 使用达梦数据库执行sql不能自动修复命令参数前缀4.8.7.18⏱️2023.03.20#I6OK4T [修复]Cron表达式*符号解析器不够严谨,如:*1111aaaaa也被解析为*4.8.7.17⏱️2023.03.20#I6OHO4 [修复] 定时任务更新作业null值默认被跳过问题4.8.7.17⏱️2023.03.20#I6OHO4 [修复] 视图引擎不支持强制转换的(object)model类型4.8.7.16⏱️2023.03.19#I6O3BD [修复] 启用请求Body重复读且在授权之前读取导致非GET/HEAD/OPTION请求异常4.8.7.15⏱️2023.03.19#I6NX9E [修复] 定时任务生成SQL语句没有处理'转义问题4.8.7.15⏱️2023.03.19#I6NXKA [修复] 数据验证ValiationTypes.GUID_OR_UUID不支持大写问题4.8.7.14⏱️2023.03.16#I6NP22 [修复]Blazor脚手架出现blazor.server.js不能加载问题(404)4.8.7.13⏱️2023.03.16#I6NOBQ [修复] 定时任务服务在停止进程时会卡住30秒问题4.8.7.8⏱️2023.03.13#I6MI9I#I6MHOU [修复] 定时任务看板删除不存在的作业触发器出现空异常4.8.7.7⏱️2023.03.1101d4466 [修复] 日志消息没有处理\n换行符对齐问题4.8.7.6⏱️2023.03.10759bcc5 [修复] 审计日志LoggingMonitor对特定参数贴有[FromServices]特性依旧记录问题4.8.7.3⏱️2023.03.0117b134e [修复]Swagger接口排序同时指定Tag和Order之后无效4.8.7.2⏱️2023.03.01#I6IQDI#I6IP66 其他更改 [调整] 视图引擎默认程序集,追加System.Collections程序集4.8.7.16⏱️2023.03.18#I6O3BD [调整] 定时任务配置选项BuilSqlType属性命为BuildSqlType4.8.7.11⏱️2023.03.1592117b8 [调整]定时任务查看作业触发器运行记录由保存10条改为5条4.8.7.7⏱️2023.03.0701d4466 [调整] 脚手架模板,默认启用主流文件类型MIME支持4.8.7.5⏱️2023.03.07e35cdab [调整] 审计日志LoggingMonitor返回值泛型字符串显示格式4.8.7.1⏱️2023.02.27df35201 文档 [新增]ASP.NET 8 集成文档 [新增].NET7 升级 .NET8文档 [更新] 定时任务文档、中间件文档、规范化结果文档、动态WebAPI文档、日志记录文档、事件总线文档、虚拟文件系统文档、Sql高级代理文档、数据库实体文档、任务队列文档、跨域文档、配置选项文档、安全授权、脚手架文档 贡献者 lampon (@lampon)!740 family520 (@family520)!739 kingling (@kinglinglive)!732!729 ksmy (@ksmy)!731 handsome_by (@handsomeboyyl)!727

优秀的个人博客,低调大师

MakuGenerator v2.1.1 发布,超好用的代码生成器

介绍 maku-generator 是一款低代码生成器,可根据自定义模板内容,快速生成代码,可实现项目的快速开发、上线,减少重复的代码编写,开发人员只需专注业务逻辑即可。采用 MIT 开源协议,完全免费开源,可免费用于商业项目等场景。 开发文档:https://maku.net/docs/maku-generator 演示环境:https://demo.maku.net/maku-generator 官网地址:https://maku.net 更新日志 升级element-plus到2.2.28 升级vite到3.2.5 升级springboot到2.7.7 优化日志打印处理 修复列表查询,页面下拉异常 项目特点 友好的代码结构及注释,便于阅读及二次开发 支持 spring boot starter,能很方便集成到第三方项目 支持通过配置数据源,快速生成 CRUD 代码,减少重复工作 支持 MySQL、Oracle、SQLServer、PostgreSQL、达梦 8 等主流的数据库 支持第三方 Java 项目包名修改,修改包名变得简单快速 支持批量导入表、批量生成代码以及同步表结构等功能 Git 仓库 Gitee 仓库:https://gitee.com/makunet/maku-generator Github 仓库:https://github.com/makunet/maku-generator 效果图

优秀的个人博客,低调大师

带你认识JDK8中超nice的Native Memory Tracking

摘要:从 OpenJDK8 起有了一个很 nice 的虚拟机内部功能: Native Memory Tracking (NMT)。 本文分享自华为云社区《Native Memory Tracking 详解(1):基础介绍》,作者:毕昇小助手。 0.引言 我们经常会好奇,我启动了一个 JVM,他到底会占据多大的内存?他的内存都消耗在哪里?为什么 JVM 使用的内存比我设置的 -Xmx 大这么多?我的内存设置参数是否合理?为什么我的 JVM 内存一直缓慢增长?为什么我的 JVM 会被 OOMKiller 等等,这都涉及到 JAVA 虚拟机对内存的一个使用情况,不如让我们来一探其中究竟。 1.简介 除去大家都熟悉的可以使用 -Xms、-Xmx 等参数设置的堆(Java Heap),JVM 还有所谓的非堆内存(Non-Heap Memory)。 可以通过一张图来简单看一下 Java 进程所使用的内存情况(简略情况): 非堆内存包括方法区和Java虚拟机内部做处理或优化所需的内存。 方法区:在所有线程之间共享,存储每个类的结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码。方法区在逻辑上(虚拟机规范)是堆的一部分,但规范并不限定实现方法区的内存位置和编译代码的管理策略,所以不同的 Java 虚拟机可能有不同的实现方式,此处我们仅讨论 HotSpot。 除了方法区域外,Java 虚拟机实现可能需要内存用于内部的处理或优化。例如,JIT编译器需要内存来存储从Java虚拟机代码转换的本机代码(储存在CodeCache中),以获得高性能。 从 OpenJDK8 起有了一个很 nice 的虚拟机内部功能: Native Memory Tracking (NMT) 。我们可以使用 NMT 来追踪了解 JVM 的内存使用详情(即上图中的 JVM Memory 部分),帮助我们排查内存增长与内存泄漏相关的问题。 2.如何使用 2.1 开启 NMT 默认情况下,NMT是处于关闭状态的,我们可以通过设置 JVM 启动参数来开启:-XX:NativeMemoryTracking=[off | summary | detail]。 注意:启用NMT会导致5% -10%的性能开销。 NMT 使用选项如下表所示: 我们注意到,如果想使用 NMT 观察 JVM 的内存使用情况,我们必须重启 JVM 来设置XX:NativeMemoryTracking 的相关选项,但是重启会使得我们丢失想要查看的现场,只能等到问题复现时才能继续观察。 笔者试图通过一种不用重启 JVM 的方式来开启 NMT ,但是很遗憾目前没有这样的功能。 JVM 启动后只有被标记为 manageable 的参数才可以动态修改或者说赋值,我们可以通过 JDK management interface (com.sun.management.HotSpotDiagnosticMXBean API) 或者 jinfo -flag 命令来进行动态修改的操作,让我们看下所有可以被修改的参数值(JDK8): java -XX:+PrintFlagsFinal | grep manageable intx CMSAbortablePrecleanWaitMillis = 100 {manageable} intx CMSTriggerInterval = -1 {manageable} intx CMSWaitDuration = 2000 {manageable} bool HeapDumpAfterFullGC = false {manageable} bool HeapDumpBeforeFullGC = false {manageable} bool HeapDumpOnOutOfMemoryError = false {manageable} ccstr HeapDumpPath = {manageable} uintx MaxHeapFreeRatio = 100 {manageable} uintx MinHeapFreeRatio = 0 {manageable} bool PrintClassHistogram = false {manageable} bool PrintClassHistogramAfterFullGC = false {manageable} bool PrintClassHistogramBeforeFullGC = false {manageable} bool PrintConcurrentLocks = false {manageable} bool PrintGC = false {manageable} bool PrintGCDateStamps = false {manageable} bool PrintGCDetails = false {manageable} bool PrintGCID = false {manageable} bool PrintGCTimeStamps = false {manageable} 很显然,其中不包含 NativeMemoryTracking 。 2.2 使用 jcmd 访问 NMT 数据 我们可以通过 jcmd 命令来很方便的查看 NMT 相关的数据: jcmd VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB] jcmd 操作 NMT 选项如下表所示: NMT 默认打印的报告是 KB 来进行呈现的,为了满足我们不同的需求,我们可以使用scale=MB | GB来更加直观的打印数据。 创建 baseline 之后使用 diff 功能可以很直观地对比出两次 NMT 数据之间的差距。 看到 shutdown 选项,笔者本能的一激灵,既然我们可以通过 shutdown 来关闭 NMT ,那为什么不能通过逆向 shutdown 功能来动态的开启 NMT 呢?笔者找到 shutdown 相关源码(以下都是基于 OpenJDK 8): # hotspot/src/share/vm/services/nmtDCmd.cpp void NMTDCmd::execute(DCmdSource source, TRAPS) { // Check NMT state // native memory tracking has to be on if (MemTracker::tracking_level() == NMT_off) { output()->print_cr("Native memory tracking is not enabled"); return; } else if (MemTracker::tracking_level() == NMT_minimal) { output()->print_cr("Native memory tracking has been shutdown"); return; } ...... //执行 shutdown 操作 else if (_shutdown.value()) { MemTracker::shutdown(); output()->print_cr("Native memory tracking has been turned off"); } ...... } # hotspot/src/share/vm/services/memTracker.cpp // Shutdown can only be issued via JCmd, and NMT JCmd is serialized by lock void MemTracker::shutdown() { // We can only shutdown NMT to minimal tracking level if it is ever on. if (tracking_level () > NMT_minimal) { transition_to(NMT_minimal); } } # hotspot/src/share/vm/services/nmtCommon.hpp // Native memory tracking level //NMT的追踪等级 enum NMT_TrackingLevel { NMT_unknown = 0xFF, NMT_off = 0x00, NMT_minimal = 0x01, NMT_summary = 0x02, NMT_detail = 0x03 }; 遗憾的是通过源码我们发现,shutdown 操作只是将 NMT 的追踪等级 tracking_level 变成了 NMT_minimal 状态(而并不是直接变成了 off 状态),注意注释:We can only shutdown NMT to minimal tracking level if it is ever on(即我们只能将NMT关闭到最低跟踪级别,如果它曾经打开)。 这就导致了如果我们没有开启过 NMT ,那就没办法通过魔改 shutdown 操作逆向打开 NMT ,因为 NMT 追踪的部分内存只在 JVM 启动初始化的阶段进行记录(如在初始化堆内存分配的过程中通过 NMT_TrackingLevel level = MemTracker::tracking_level(); 来获取 NMT 的追踪等级,视等级来记录内存使用情况),JVM 启动之后再开启 NMT 这部分内存的使用情况就无法记录,所以目前来看,还是只能在重启 JVM 后开启 NMT。 至于提供 shutdown 功能的原因,应该就是让用户在开启 NMT 功能之后如果想要关闭,不用再次重启 JVM 进程。shutdown 会清理虚拟内存用来追踪的数据结构,并停止一些追踪的操作(如记录 malloc 内存的分配)来降低开启 NMT 带来的性能耗损,并且通过源码可以发现 tracking_level 变成 NMT_minimal 状态后也不会再执行 jcmd VM.native_memory 命令相关的操作。 2.3 虚拟机退出时获取 NMT 数据 除了在虚拟机运行时获取 NMT 数据,我们还可以通过两个参数:-XX:+UnlockDiagnosticVMOptions和-XX:+PrintNMTStatistics ,来获取虚拟机退出时内存使用情况的数据(输出数据的详细程度取决于你设定的跟踪级别,如 summary/detail 等)。 -XX:+UnlockDiagnosticVMOptions:解锁用于诊断 JVM 的选项,默认关闭。 -XX:+PrintNMTStatistics:当启用 NMT 时,在虚拟机退出时打印内存使用情况,默认关闭,需要开启前置参数 -XX:+UnlockDiagnosticVMOptions才能正常使用。 3.NMT 内存 & OS 内存概念差异性 我们可以做一个简单的测试,使用如下参数启动 JVM : -Xmx1G -Xms1G -XX:+UseG1GC -XX:MaxMetaspaceSize=256m -XX:MaxDirectMemorySize=256m -XX:ReservedCodeCacheSize=256M -XX:NativeMemoryTracking=detail 然后使用 NMT 查看内存使用情况(因各环境资源参数不一样,部分未明确设置数据可能由虚拟机根据资源自行计算得出,以下数据仅供参考): jcmd VM.native_memory detail NMT 会输出如下日志: Native Memory Tracking: Total: reserved=2813709KB, committed=1497485KB - Java Heap (reserved=1048576KB, committed=1048576KB) (mmap: reserved=1048576KB, committed=1048576KB) - Class (reserved=1056899KB, committed=4995KB) (classes #442) (malloc=131KB #259) (mmap: reserved=1056768KB, committed=4864KB) - Thread (reserved=258568KB, committed=258568KB) (thread #127) (stack: reserved=258048KB, committed=258048KB) (malloc=390KB #711) (arena=130KB #234) - Code (reserved=266273KB, committed=4001KB) (malloc=33KB #309) (mmap: reserved=266240KB, committed=3968KB) - GC (reserved=164403KB, committed=164403KB) (malloc=92723KB #6540) (mmap: reserved=71680KB, committed=71680KB) - Compiler (reserved=152KB, committed=152KB) (malloc=4KB #36) (arena=148KB #21) - Internal (reserved=14859KB, committed=14859KB) (malloc=14827KB #3632) (mmap: reserved=32KB, committed=32KB) - Symbol (reserved=1423KB, committed=1423KB) (malloc=936KB #111) (arena=488KB #1) - Native Memory Tracking (reserved=330KB, committed=330KB) (malloc=118KB #1641) (tracking overhead=211KB) - Arena Chunk (reserved=178KB, committed=178KB) (malloc=178KB) - Unknown (reserved=2048KB, committed=0KB) (mmap: reserved=2048KB, committed=0KB) ...... 大家可能会发现 NMT 所追踪的内存(即 JVM 中的 Reserved、Committed)与操作系统 OS (此处指Linux)的内存概念存在一定的差异性。 首先按我们理解的操作系统的概念: 操作系统对内存的分配管理典型地分为两个阶段:保留(reserve)和提交(commit)。保留阶段告知系统从某一地址开始到后面的dwSize大小的连续虚拟内存需要供程序使用,进程其他分配内存的操作不得使用这段内存;提交阶段将虚拟地址映射到对应的真实物理内存中,这样这块内存就可以正常使用 [1]。 如果使用 top 或者 smem 等命令查看刚才启动的 JVM 进程会发现: top PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 36257 dou+ 20 0 10.8g 54200 17668 S 99.7 0.0 13:04.15 java 此时疑问就产生了,为什么 NMT 中的 committed ,即日志详情中 Total: reserved=2813709KB, committed=1497485KB 中的 1497485KB 与 top 中 RES 的大小54200KB 存在如此大的差异? 使用 man 查看 top 中 RES 的概念(不同版本 Linux 可能不同): RES -- Resident Memory Size (KiB) A subset of the virtual address space (VIRT) representing the non-swapped physical memory a task is currently using. It is also the sum of the RSan, RSfd and RSsh fields. It can include private anonymous pages, private pages mapped to files (including program images and shared libraries) plus shared anonymous pages. All such memory is backed by the swap file represented separately under SWAP. Lastly, this field may also include shared file-backed pages which, when modified, act as a dedicated swap file and thus will never impact SWAP. RES 表示任务当前使用的非交换物理内存(此时未发生swap),那按对操作系统 commit 提交内存的理解,这两者貌似应该对上,为何现在差距那么大呢? 笔者一开始猜测是 JVM 的 uncommit 机制(如 JEP 346[2],支持 G1 在空闲时自动将 Java 堆内存返回给操作系统,BiSheng JDK 对此做了增强与改进[3])造成的,JVM 在 uncommit 将内存返还给 OS 之后,NMT 没有除去返还的内存导致统计错误。 但是在翻阅了源码之后发现,G1 在 shrink 缩容的时候,通常调用链路如下: G1CollectedHeap::shrink-> G1CollectedHeap::shrink_helper-> HeapRegionManager::shrink_by-> HeapRegionManager::uncommit_regions-> G1PageBasedVirtualSpace::uncommit-> G1PageBasedVirtualSpace::uncommit_internal-> os::uncommit_memory 忽略细节,uncommit 会在最后调用 os::uncommit_memory ,查看 os::uncommit_memory 源码: bool os::uncommit_memory(char* addr, size_t bytes) { bool res; if (MemTracker::tracking_level() > NMT_minimal) { Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); res = pd_uncommit_memory(addr, bytes); if (res) { tkr.record((address)addr, bytes); } } else { res = pd_uncommit_memory(addr, bytes); } return res; } 可以发现在返还 OS 内存之后,MemTracker 是进行了统计的,所以此处的误差不是由 uncommit 机制造成的。 既然如此,那又是由什么原因造成的呢?笔者在追踪 JVM 的内存分配逻辑时发现了一些端倪,此处以Code Cache(存放 JVM 生成的 native code、JIT编译、JNI 等都会编译代码到 native code,其中 JIT 生成的 native code 占用了 Code Cache 的绝大部分空间)的初始化分配为例,其大致调用链路为下: InitializeJVM-> Thread::vreate_vm-> init_globals-> codeCache_init-> CodeCache::initialize-> CodeHeap::reserve-> VirtualSpace::initialize-> VirtualSpace::initialize_with_granularity-> VirtualSpace::expand_by-> os::commit_memory 查看 os::commit_memory 相关源码: bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, bool executable) { bool res = os::pd_commit_memory(addr, size, alignment_hint, executable); if (res) { MemTracker::record_virtual_memory_commit((address)addr, size, CALLER_PC); } return res; } 我们发现 MemTracker 在此记录了 commit 的内存供 NMT 用以统计计算,继续查看 os::pd_commit_memory 源码,可以发现其调用了 os::Linux::commit_memory_impl 函数。 查看 os::Linux::commit_memory_impl 源码: int os::Linux::commit_memory_impl(char* addr, size_t size, bool exec) { int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); if (res != (uintptr_t) MAP_FAILED) { if (UseNUMAInterleaving) { numa_make_global(addr, size); } return 0; } int err = errno; // save errno from mmap() call above if (!recoverable_mmap_error(err)) { warn_fail_commit_memory(addr, size, exec, err); vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "committing reserved memory."); } return err; } 问题的原因就在 uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); 这段代码上。 我们发现,此时申请内存执行的是 mmap 函数,并且传递的 port 参数是 PROT_READ|PROT_WRITE|PROT_EXEC 或 PROT_READ|PROT_WRITE ,使用 man 查看 mmap ,其中相关描述为: The prot argument describes the desired memory protection of the mapping (and must not conflict with the open mode of the file). It is either PROT_NONE or the bitwise OR of one or more of the following flags: PROT_EXEC Pages may be executed. PROT_READ Pages may be read. PROT_WRITE Pages may be written. PROT_NONE Pages may not be accessed. 由此我们可以看出,JVM 中所谓的 commit 内存,只是将内存mmaped映射为可读可写可执行的状态!而在 Linux 中,在分配内存时又是 lazy allocation 的机制,只有在进程真正访问时才分配真实的物理内存。所以 NMT 中所统计的 committed 并不是对应的真实的物理内存,自然与 RES 等统计方式无法对应起来。 所以 JVM 为我们提供了一个参数 -XX:+AlwaysPreTouch,使我们可以在启动之初就按照内存页粒度都访问一遍 Heap,强制为其分配物理内存以减少运行时再分配内存造成的延迟(但是相应的会影响 JVM 进程初始化启动的时间),查看相关代码: void os::pretouch_memory(char* start, char* end) { for (volatile char *p = start; p < end; p += os::vm_page_size()) { *p = 0; } } 让我们来验证下,开启 -XX:+AlwaysPreTouch 前后的效果。 NMT 的 heap 地址范围: Virtual memory map: [0x00000000c0000000 - 0x0000000100000000] reserved 1048576KB for Java Heap from [0x0000ffff93ea36d8] ReservedHeapSpace::ReservedHeapSpace(unsigned long, unsigned long, bool, char*)+0xb8 [0x0000ffff93e67f68] Universe::reserve_heap(unsigned long, unsigned long)+0x2d0 [0x0000ffff93898f28] G1CollectedHeap::initialize()+0x188 [0x0000ffff93e68594] Universe::initialize_heap()+0x15c [0x00000000c0000000 - 0x0000000100000000] committed 1048576KB from [0x0000ffff938bbe8c] G1PageBasedVirtualSpace::commit_internal(unsigned long, unsigned long)+0x14c [0x0000ffff938bc08c] G1PageBasedVirtualSpace::commit(unsigned long, unsigned long)+0x11c [0x0000ffff938bf774] G1RegionsLargerThanCommitSizeMapper::commit_regions(unsigned int, unsigned long)+0x5c [0x0000ffff93943f54] HeapRegionManager::commit_regions(unsigned int, unsigned long)+0x7c 对应该地址的/proc/{pid}/smaps: //开启前 //开启后 c0000000-100080000 rw-p 00000000 00:00 0 c0000000-100080000 rw-p 00000000 00:00 0 Size: 1049088 kB Size: 1049088 kB KernelPageSize: 4 kB KernelPageSize: 4 kB MMUPageSize: 4 kB MMUPageSize: 4 kB Rss: 792 kB Rss: 1049088 kB Pss: 792 kB Pss: 1049088 kB Shared_Clean: 0 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Clean: 0 kB Private_Dirty: 792 kB Private_Dirty: 1049088 kB Referenced: 792 kB Referenced: 1048520 kB Anonymous: 792 kB Anonymous: 1049088 kB LazyFree: 0 kB LazyFree: 0 kB AnonHugePages: 0 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 0 kB Swap: 0 kB SwapPss: 0 kB SwapPss: 0 kB Locked: 0 kB Locked: 0 kB VmFlags: rd wr mr mw me ac VmFlags: rd wr mr mw me ac 对应的/proc/{pid}/status: //开启前 //开启后 ... ... VmHWM: 54136 kB VmHWM: 1179476 kB VmRSS: 54136 kB VmRSS: 1179476 kB ... ... VmSwap: 0 kB VmSwap: 0 kB ... 开启参数后的 top: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 85376 dou+ 20 0 10.8g 1.1g 17784 S 99.7 0.4 14:56.31 java 观察对比我们可以发现,开启 AlwaysPreTouch 参数后,NMT 统计的 commited 已经与 top 中的 RES 差不多了,之所以不完全相同是因为该参数只能 Pre-touch 分配 Java heap 的物理内存,至于其他的非 heap 的内存,还是受到 lazy allocation 机制的影响。 同理我们可以简单看下 JVM 的 reserve 机制: # hotspot/src/share/vm/runtime/os.cpp char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint, MEMFLAGS flags) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); MemTracker::record_virtual_memory_type((address)result, flags); } return result; } # hotspot/src/os/linux/vm/os_linux.cpp char* os::pd_reserve_memory(size_t bytes, char* requested_addr, size_t alignment_hint) { return anon_mmap(requested_addr, bytes, (requested_addr != NULL)); } static char* anon_mmap(char* requested_addr, size_t bytes, bool fixed) { ...... addr = (char*)::mmap(requested_addr, bytes, PROT_NONE, flags, -1, 0); ...... } reserve 通过 mmap(requested_addr, bytes, PROT_NONE, flags, -1, 0); 来将内存映射为 PROT_NONE,这样其他的 mmap/malloc 等就不能调用使用,从而达到了 guard memory 或者说 guard pages 的目的。 OpenJDK 社区其实也注意到了 NMT 内存与 OS 内存差异性的问题,所以社区也提出了相应的 Enhancement 来增强功能: 1.JDK-8249666[4] : 目前 NMT 将分配的内存显示为 Reserved 或 Committed。而在 top 或 pmap 的输出中,首次使用(即 touch)之前 Reserved 和 Committed 的内存都将显示为 Virtual memory。只有在内存页(通常是4k)首次写入后,它才会消耗物理内存,并出现在 top/pmap 输出的 “常驻内存”(即 RSS)中。 当前NMT输出的主要问题是,它无法区分已 touch 和未 touch 的 Committed 内存。 该 Enhancement 提出可以使用 mincore() [5]来查找 NMT 的 Committed 中 RSS 的部分,mincore() 系统调用让一个进程能够确定一块虚拟内存区域中的分页是否驻留在物理内存中。mincore()已在JDK-8191369 NMT:增强线程堆栈跟踪中实现,需要将其扩展到所有其他类型的内存中(如 Java 堆)。 遗憾的是该 Enhancement 至今仍是 Unresolved 状态。 2.JDK-8191369[6] : 1 中提到的 NMT:增强线程堆栈跟踪。使用 mincore() 来追踪驻留在物理内存中的线程堆栈的大小,用以解决线程堆栈追踪时有时会夸大内存使用情况的痛点。 该 Enhancement 已经在 JDK11 中实现。 参考 https://weread.qq.com/web/reader/53032310717f44515302749k37632cd021737693cfc7149 http://openjdk.java.net/jeps/346 https://gitee.com/openeuler/bishengjdk-8/wikis/G1GC内存伸缩特性介绍?sort_id=3340035 https://bugs.openjdk.org/browse/JDK-8249666 https://man7.org/linux/man-pages/man2/mincore.2.html https://bugs.openjdk.org/browse/JDK-8191369 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

Timescale 完成 C 轮融资,估值已超 10 亿美元

时序数据库 TimescaleDB 背后的公司 Timescale 近日在 C 轮融资中筹集了 1.1 亿美元,使得总融资金额达到 1.8 亿美元。Timescale 成立短短 7 年时间的估值就超过 10 亿美元,已成为数据库领域的又一独角兽企业。 本轮融资由 Tiger Global 领投,所有现有投资者 Benchmark、New Enterprise Associates、Redpoint Ventures、Icon Ventures 和 Two Sigma Ventures 都参与跟投。 在 2021 年、2019 年和 2018 年,Timescale 曾分别完成了 4000 万美元、1500 万美元和 1600 万美元的融资。此次 C 轮融资相比过去几轮金额都高,这也标志着投资者对 Timescale 基础业务十分看好(在过去的两年里,Timescale 的社区增长了 7 倍,收入增长了 20 倍)。 获得该笔融资后,Timescale 计划利用这些资金增加对产品、工程和研发方面的投入,持续发展团队,并为扩大 Timescale 社区、客户,以及为全球开发者服务作出努力。 Timescale 创始人兼首席执行官 Ajay Kulkarni 表示:“时序数据无处不在,基于时序数据构建的应用需要一种新型数据库。这笔资金和 Timescale 的飞速增长证明 TimescaleDB 就是答案。” Timescale 目前为使用 TimescaleDB 的 500 多家付费客户和社区中数万家其他组织提供服务,其中包括苹果、思科、康卡斯特、漫威、通用电气、IBM、微软、特斯拉、三星、施耐德电气、Uber、沃尔玛等公司。

优秀的个人博客,低调大师

微软员工利用漏洞盗取超千万美元Xbox礼品卡

近日,外媒Windows Central报道了一则关于微软员工利用漏洞非法获利的消息。一名工程师被微软雇来测试电子商务系统,利用系统中的一个漏洞,该工程师能够通过测试中的方法订购到Xbox电子礼品卡。他用这一方法订购了超过1000万美元的Xbox礼品卡。 这名叫做沃罗德米尔·克瓦舒克(Volodymyr Kvashuk)的工程师在微软公司通用商店团队担任工程师,测试公司的电子商务系统,他利用漏洞使用虚假的信用卡购买到了真实的Xbox电子礼品卡,他还为此制作了一个程序来源源不断地获取Xbox礼品卡地序列号。 2018年2月份,微软的UST欺诈调查打击小组发现了使用数字货币购买Xbox Live订阅量的可疑增长,并顺藤摸瓜抓到了克瓦舒克。现在,这名工程师被判服刑到2027年,刑期结束后还可能面临被遣送回其祖国乌克兰,并且还将赔偿微软公司830万美元。 克瓦舒克在获得这些数字礼品卡后,将其打折出售。检察官表示,其行为已经对Xbox礼品卡在转售市场上的全球价格波动产生了影响。

优秀的个人博客,低调大师

超7亿领英用户数据暗网出售

近日,研究人员发现有超过7亿领英用户数据在暗网出售,是领英史上最大规模的数据泄露事件。 事件分析 6月22日,有黑客在暗网平台出售超过7亿的领英用户数据,并发布了一个包含100万领英用户的样本数据集。 研究人员查看该样本发现其中含有以下信息: 邮箱; 姓名; 电话号码; 家庭地址; 地理位置记录; 领英用户名和介绍的URL; 个人和职业经验、背景信息; 性别; 其他社交媒体账号和用户名。 这是领英史上最大规模的数据泄露事件。 该用户称完整的数据库中包含有7亿领英用户的个人信息。因为领英官方声称有7.56亿用户,也就是说有约92%的领英用户可以在该泄露的数据库中检索到个人的信息。 下面是该黑客给出的样本数据: 从中可以看到用户全名、领英用户名、Facebook用户名、邮件地址、手机号码、职业数据、工资数据等。 根据研究人员的分析和对该数据样本与公开数据的对比发现,数据应该是真实的,并且与现实用户是关联的。此外,该数据也是最新的,因为包含了2020到2021年的一些样本。 研究人员在黑客给出的数据样本中并没有发现登陆凭证或金融数据,但攻击者仍然有可能利用这些数据来进行获利。 数据来源分析 研究人员与发布数据的黑客进行了联系,该黑客称数据是利用领英API获取的用户上传到领英网站的信息。下面是研究人员与该黑客在telegram上的对话: 可以看出黑客对完整数据集要价5000美元,称该数据集是通过领英API获取的。 领英回应 领英已经给出官方回复称,通过初步分析发现并非所有数据都是通过领英API获取的,相反,有部分数据是来自其他来源的。而且这并非领英数据泄露事件,具体结果有待进一步调查。 本文翻译自:https://restoreprivacy.com/linkedin-data-leak-700-million-users 鸿蒙官方战略合作共建――HarmonyOS技术社区 【责任编辑:赵宁宁 TEL:(010)68476606】

优秀的个人博客,低调大师

BeetlSQL 3.2.8 发布,超好用的 Java 数据库访问工具

本次发布增加了一个贴心功能,可以限制Mapper方法中的SQL长度,以避免过长SQL导致难以维护 配置属性 MAPPER_SQL_MAX_LENGTH,限制Mapper中的SQL长度,默认不限制 代码自动生成的ID使用@AssingID 无论是JAP,还是SpringData,还是MyBatis,还是BeetSQL,都支持Mapper中使用注解指明SQL语句,以BeetlSQL为例子 @Sql("select * from user where dept_id=?") List<User> selectByDept(Integer deptId); @Template("select * from user where dept_id=#{deptId}") List<User> selectByDept2(Integer deptId); 原则上应该尽量保持sql语句短小,过长的sql语句应该放到文件里维护。BeetlSQL提供了一个运行时刻检测sql语句长度,如果过长,则拒绝执行。 <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetlsql</artifactId> <version>3.2.8-RELEASE</version> </dependency> BeetlSQL 的目标是提供开发高效,维护高效,运行高效的数据库访问框架,以我20年在电信,金融以及互联网天天CRUD的经验总结得来的框架,适用范围广。目前支持的数据库如下 传统数据库:MySQL,MariaDB,Oralce,Postgres,DB2,SQL Server,H2,SQLite,Derby,神通,达梦,华为高斯,人大金仓,PolarDB 等 大数据:HBase,ClickHouse,Cassandar,Hive 物联网时序数据库:Machbase,TD-Engine,IotDB SQL查询引擎:Drill,Presto,Druid 内存数据库:ignite,CouchBase 事务支持本地和全局,以及Saga事务,也可以配合第三方事务管理器。 阅读文档源码和例子性能测试

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册