首页 文章 精选 留言 我的

精选列表

搜索[不可见索引],共10000篇文章
优秀的个人博客,低调大师

数据库领域错觉:MongoDB 不火了?

近日,MongoDB 5.0 正式发布,推出了时序集合等重磅新特性,进一步拓宽适用版图。与此同时,这款分布式文档数据库在 DB-Engines 最新公布的 7 月数据库排行榜中高居第 5 位,且分数还在不断增加,成为国际数据库市场上最受欢迎的 NoSQL 数据库产品。 自 MongoDB 公司于 2018 年更改开源协议之后,MongoDB 曾一度陷入巨大的争议漩涡,导致了当时很多企业用户的弃用,不少人对 MongoDB 的发展持消极态度。三年过去,MongoDB 却以持续增长的态势稳坐 NoSQL 数据库一哥的位置,出乎了很多人的意料。 MongoDB 在国内的现状 MongoDB 中文社区创始人、前 MongoDB 大中华区技术总监唐建法(TJ)是资深的数据库技术专家,多年来一直从事 MongoDB 的相关工作。早在 2016 年时,TJ 曾指出国内对 MongoDB 的认知程度不够,以至于大部分时候都是使用在非关键型应用场景。发展到今天,TJ 一路见证了 MongoDB 在国内的成长,越来越多的国内企业和开发者开始接受和使用 MongoDB。 TJ 表示,自己虽然已经离开了 MongoDB 团队,但仍作为 MongoDB 中文社区创始人,一直在关注着 MongoDB 在国内的发展动向。 “MongoDB 这些年来在国内的发展一直是非常棒的,我们观察到很多企业都已经接受了其在很多关键场景可以发挥独特价值的地方,我身边一半的创业公司都在使用 MongoDB。”TJ 说。在金融场景,中国银行、招商银行以及太平洋保险、泰康等这些头部金融行业,都开始使用 MongoDB;在很多公有云平台,MongoDB 也成为除了 MySQL 之外使用最广泛的一个数据库之一。 而在社区方面,TJ 创立的 MongoDB 中文社区也已经从最初的几十人发展到了今天的数万人。TJ 表示,在疫情解除后,社区的技术交流活动也会回归正常,今年社区在长沙、杭州、北京等地举办的技术交流活动也吸引了大量的 MongoDB 爱好者参加。 如今的 MongoDB 在国内的发展可谓是欣欣向荣。 MongoDB 的特色 在传统关系型数据库老而弥坚,新兴 NewSQL 数据库风头正盛的今天,MongoDB 又是凭借什么优势在数据库市场中立足的呢? TJ 告诉我们,MongoDB 是一个比较通用的多用途分布式文档数据库产品。与其他主流数据库相比,它的核心亮点是其弹性 JSON 模型,对应用开发非常友好,可以数量级的降低数据库开发的工作量。 经过这些年的优化迭代,MongoDB 可以像 MySQL 一样,支持 ACID 事务,可以作为大部分 APP 的后台数据库。它原生的 Shared Nothing 的分片架构,可以提供非常强大的扩展能力,支持类似于字节跳动这样海量用户的高并发访问。 MongoDB 通过 RAFT 协议来支持多节点互备,而不是传统的通过落盘来保证数据的持久性,这样能够以接近内存数据库的速度来为那些对响应延迟极低的应用提供支持,用户往往不再需要 Redis 这样的专用缓存。 此外,它的 Change Stream 功能就像一个 Mini-Kafka 一样,能够为 pub-sub 场景提供一个非常方便的队列功能。 正是看中 MongoDB 的这些特性,TJ 决定将其用来作为实时数据服务平台的存储方案,开启了自己的创业之路 —— 创办 Tapdata。 MongoDB:创业者的不二之选 Tapdata 想要解决的问题是传统企业 IT 架构的“数据孤岛”现象,即为客户提供实时打通多源异构数据库的能力。 事实上,这些年来为解决“数据孤岛”出现的产品并不少见,从数仓、数据湖再到数据中台,可以发现,三者支持的核心业务场景还是偏 BI 报表、各种数据分析等 OLAP 场景,重在对历史数据做洞察和分析。而一个能为企业提供即时数据、用于 OLTP 业务支撑的实时数据平台却少之又少。正是看中了这一市场空白,Tapdata 决定以实时数据为服务,打造一个面向 TP 的实时 DaaS 平台。 不过 TJ 也指出,Tapdata 的 DaaS 平台与其他数仓和大数据平台并不是非此即彼的关系,因为 DaaS 是以数据服务为导向的数据平台,并不企图大而全地支撑起所有数据业务,因此可以和数据湖和数仓形成上下游关系,为其提供完整、统一、准确的实时数据。用 TJ 的话说就是:“我只把数据像自来水一样给到你,你把‘水’拿过去以后,是用去做饮料还是啤酒,由你来定。”这也是 Tapdata 创立的初衷:Make Your Data on Tap! TJ 介绍,相比于动辄需要 5-10 个开源技术栈集成起来的大数据平台,Tapdata 实时数据服务平台依赖 MongoDB 的特性实现了部署运维轻,学习成本低等高度产品化的优点。其中的核心技术优势,则是实现了覆盖数据采集到存储过程的全链路实时。 Tapdata 目前面向的数据管理人员、应用开发或者架构师,在定位上更偏向基础软件。关于如何让市场更好的理解这一点并接受,TJ 表示有一个明确的“开放+开源”的路线图。 开源商业化的探索 在基础架构软件领域,开源是最快提高市场接受度的一种模式。2021 年可以说是开源商业化爆发的一年,根据 oss capital 的统计,截止到 2021 年上半年,仅仅 6 个月的时间里风投公司对开源商业公司的投资额已经超过了 50 亿美元,全年产品融资额已经达到甚至超越此前 20 年的总和。但是作为一个从市值 230 亿美元的开源商业化大坑里爬出来的老兵,TJ 表示他还在琢磨 Tapdata 开源后最合适的商业化模式。 据悉,在代码开源之前,Tapdata 会通过云上开放的方式,以另一种方式将核心产品能力免费提供给社区。Tapdata Cloud 已于近日正式推出公测版(http://cloud.tapdata.net) , 目前这个版本还只是 Tapdata产品的一部分功能,但是已经可以独立完成多达十几种数据库的异构数据同步能力,为新业务扩展,缓存加速, 全文检索,数据库备份容灾等很多新型业务场景提供生产级的支撑。 TJ 表示 Tapdata 的这款云产品其实已经在数月前成功和移动公有云 ecloud 合作上线,为移动云上和云下所有的数据库提供上云和云间同步迁移能力。所以大家可以放心使用。Tapdata Cloud 目前的版本现在和将来都不会收费。由于其架构的特性,运营管理成本完全可以将持续由 Tapdata 公司来承担。TJ 希望通过免费云版开放来让大家体会到实时数据的巨大价值,并能够进一步了解并采用 Tapdata 的 Real Time DaaS 数据架构及产品。 下一步,在完成必要的准备工作后,Tapdata 将会把核心模块的代码开源,使得不能上云的用户也能使用到 Tapdata 的技术。也是通过这样的策略,Tapdata 将海外市场作为未来增长的重要方向。事实上,在尚未开源和推广的情况下,Tapdata 已经获得了若干海外付费客户,并于今年 7 月获得了数千万美元的融资。 最后,TJ 也为自己的创业团队打了个小广告:“Tapdata 正处于高速发展的时期,希望能有更多技术大牛加入我们,我们会提供书面期权等丰厚的福利。” 嘉宾简介 唐建法(TJ),MongoDB 中文社区主席,Tapdata 创始人,前 MongoDB 大中华区技术总监 8 月 1 日,TJ 将作为全球开源技术峰会 GOTC 2021 深圳站的演讲嘉宾,在「分布式数据库与存储」分论坛上带来主题为“基于 MongoDB 构建实时数据中台的技术实现和挑战” 的精彩演讲。TJ 将在本次分享中为大家讲解什么是实时数据中台,核心技术需求都有哪些,技术选型的主要依据什么,以及快速落地的方案。通过本次分享你将了解基于 MongoDB 的特点和特性,快速落地实施数据中台系统的关键技术细节。 详情请查看:https://gotc.oschina.net/forum/lists/2/34

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

自从尝了 Rust,Java 突然不香了

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 相对而言,Rust 是软件行业中比较新的一门编程语言,如果从语法上来比较,该语言与 C++ 其实非常类似,但从另一方面而言,Rust 能更高效地提供许多功能来保证性能和安全。而且,Rust 还能在无需使用传统的垃圾收集系统的情况下保证内存的安全性。 Rust 语言原本是 Mozilla 员工 Graydon Hoare 的私人项目,Graydon Hoare 当时是 Mozilla 研究部门的一位经验丰富的 IT 科学家。2009 年,Mozilla 开始赞助这个计划,并且在 2010 年首次揭露了它的存在。 随着越来越多设计者的加入,他们为该编程语言打造了浏览器引擎,并设计了 Rust 编译器。Rust 编译器是一款免费和开源的编程软件,受 MIT 许可证和 Apache 许可证保护。自 2016 年起,由于许多开发人员开始选择 Rust 而不是 Java 来进行栈溢出(Stack overflow)开发,Rust 语言开始成为人们关注的焦点。 1. 为什么 Rust 受到许多开发者的青睐? Rust 具有更强大的高并发性和高安全性,堪称栈溢出开发的完美选择。对函数的优秀控制能力和对内存布局的完美运用,这让Rust 成为一种面向性能的编程语言。使用 Rust,你可以事半功倍地维护系统的完整性和安全性,此外,在语法、内存安全性以及内存管理上 Rust 也有着不俗表现。 语法易学 由于 Rust 与软件行业中最流行的 C++ 语言的相似性以及其简单的语法,让学习和理解这门语言变得非常容易,甚至对于初学者而言也简单易懂。Rust 的语法与 C 和 C++ 编程有很多相似之处,比如 if-else、while、for、return 等关键字的用法,而 Rust 中一些关键字还使用了模式匹配技术,这使得这门语言更容易上手。 尽管语法非常相似,就函数和功能方面而言,Rust 语言做得更广更深。该编程语言的“广”在于,你可以发现每个函数体中所包含的几乎所有部分,包括控制流操作符,本身都是以表达式来呈现的。简而言之,如果你已经掌握了 C 或 C++,在对这些编程语言的一般理解标准下,Rust 能帮助你完成更多工作。 内存安全 说到 Rust 的安全特性,它被专门设计为保护内存安全,它在安全代码中不允许使用空指针、悬垂指针和数据竞争。如果你需要对一个数据值进行初始化,那么只能通过一系列固定的形式来完成初始化,它要求在函数开始前初始化所有的输入。几乎所有其他语言都允许指针以有效形式或 Null 形式存在,但 Rust 提供了一组额外的特性集来测试指针是否有值。 非传统的特性 Rust 还引入了一些额外添加的语法和功能来管理函数本身的生命周期,另一个方面,如果需要编写一些不安全的代码,可以使用 Unsafe Rust 功能来对其进行限制,而所有权功能作用于所有的值,让每个值只可以有一个唯一的所有权属主,值的有效范围和该唯一所有权属主的有效范围保持一致。值可以通过不可变引用关键字 &T 进行传递,也可以通过可变引用关键字 &mut T 来完成传递。Rust 编译器在编译时执行这些规则,并同时追踪所有引用的有效性。 内存管理 Rust 不像 Java 或.Net 等编程语言那样使用传统的自动垃圾回收系统,Rust 也不像 Swift 或 C 等编程语言那样使用自动引用系统。Rust 是通过其独有的 RAII(资源获取即初始化)规范方法来管理内存和其他资源的。此外,Rust 还使用最优引用计数方法来对内存分配进行优化,它还支持值的堆栈分配方法而非隐式装箱转换。 基于特征(Traits)和结构化类型来实现 Rust 的系统是基于特征(Traits)和结构化类型来实现的。在 Rust 中,类是用关键字 impl 来定义的。继承和多态是由特征提供的,并允许开发人员使用方法和混合实现。此外,结构化类型还用于定义不同类型的字段。实现和特征不能进行自我定义,它们只能提供继承数据。Rust 还支持接口继承,但是只允许使用复合集成来替代实现继承。 2. Rust 代码示例 Hello World 函数 fn main() { println!("Hello World!"); } 递归函数 fn factorial(i: u64) -> u64 { match i { 0 => 1, n => n * factorial(n-1) }} 迭代函数 fn factorial(i: u64) -> u64 { let mut acc = 1; for num in 2..=i { acc *= num; } acc } 3. 当下使用 Rust 的主流项目 如果你知道现在有哪些软件和应用程序是用 Rust 语言开发的,那么你可能会比以前更加信赖这种编程语言。Rust 已经被用于开发很多赫赫有名的主流应用程序,有如下: Mozilla Firefox 浏览器; Discord(一款游戏聊天应用); Gecko 浏览器; Tor 浏览器; GNOME Fractal(一款即时消息客户端); 谷歌 Fuchsia 操作系统; Redox OS; Rocket Web Framework; Servo(一款由 Mozilla 开发的网页浏览器排版引擎); Terminus DB(一款数据库软件); Libra(数字货币); OpenDNS; 4.Rust 的独有特性 十分接近基本的 C 和 C++ 编程语言和语法; 做代码分析时,即使对于第三方代码阅读器而言,也能轻松解析其中引用的语义; 所有权系统设计非常合理,这也让 Rust 变得特点鲜明; 由于有逻辑内存分配、引用处理和内存管理等特性,Rust 内置的包管理器 Cargo 功能非常强大; Rust 的编译器自身功能令人惊叹。 5. Rust 比 Java 好在哪? 即使对于一个中等水平的程序员而言,从 Java 切换到 Rust 也是一件很容易的事情。从一开始学习,你就会觉得概念和语法似曾相识,这能让学习和编程都变得十分容易。因此,尽管 Rust 的确在技术上朝前迈出了一大步,但程序员在编程习惯上并不需要做出很大的调整。 使用 Rust 语言,你可以放心大胆地去探索各式类型新颖的复杂项目,而之前由于 Java 语言的复杂性,你不敢轻易尝试这些项目。对于独立开发者来说,完美的资源分配和良好的内存管理是必备之选,这的确是 Rust 一个较大的优点。 另一方面,如今所有行业都建设在 IT 基础之上,无论你是否是一名专业编程人员,在任何需要挖掘创造力的技术领域,都需要借助软件编程。因此,复杂的编码语言让非专业程序员很难轻松地编写出所需代码,而 Rust 正好可以为这类人提供解决方案。即使是业余程序员和初学者,也可以轻松地学习并在逻辑上理解这门编程语言,从而磨砺自己的技能并在各行各业中去尽力发挥他们的创造力。 6. 结束语 从 Java 切换到 Rust 很简单,而且顺理成章,只需要在编程语言上做出一些调整就能完成切换。而且这种切换并不会让你忘记所有已经掌握的 Java 技能,因此,如果需要,你还可以随时切换回 Java。但是,如果你坚持使用 Rust 的话,你的生产效率将会变得更高,资源使用率将得到优化,代码安全性会变得更好,而且最重要的一点是,你能享受Rust 提供的诸多额外特性和功能。 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/live 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-07-10本文作者:Sayan Dey本文来自:“cocoachina”,了解相关信息可以关注“cocoachina”

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

jvm原理解析——不疯魔不成活

摘要: 作为一名java开发人员,如果有人问你java是什么?java是如何运行的?你该如何回答,事实上java是有Java语言、class文件、jvm、Java API共同组成。 java程序运行 *.java文件-->编译器-->*.class文件-->线程启动(main)-->jvm-->操作系统-->硬件 通过上面的流程我们可以看出java程序的执行顺序,那么jvm到底是什么,class文件到底是如何在jvm中运行就显得很重要了。 jvm原理 什么是jvm openjdk源码地址http://hg.openjdk.java.net/jdk9 JVM是一个计算机模型,JVM对Java可执行代码,即字节码(Bytecode)的格式给出了明确的规格。这一规格包括操作码和操作数的语法(也就是cpu指令集)和数值、标识符的数值表示方式、以及Java类文件中的Java对象、常量缓冲池在JVM的存储映象。 JVM的组成 JVM指令系统、JVM寄存器、JVM 栈结构、JVM 碎片回收堆、JVM 存储区 JVM指令 Java指令也是由操作码和操作数两部分组成,与RISC CPU采用的编码方式是一致的,也就是精简指令集,目前UNIX、Linux、MacOS系统使用RISC,我们目前知道的x86架构CPU使用的CISC编码,也就是复杂指令集。 JVM寄存器 1.pc程序计数器 2.optop操作数栈顶指针 3.frame当前执行环境指针 4.vars指向当前执行环境中第一个局部变量的指针 jvm的装载 windows操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步来完成JVM环境。 1.创建JVM装载环境和配置 2.装载JVM.dll(C:Program FilesJavajre1.8.0_151inserver linux在jre/lib/server下) 3.初始化JVM.dll并挂接到JNIENV(JNI调用接口)实例 4.调用JNIEnv实例装载并处理class类。 JVM虚拟机相当于x86计算机系统,Java解释器相当于x86CPU JVM运行数据 JVM定义了若干个程序执行期间使用的数据区域。这个区域里的一些数据在JVM启动的时候创建,在JVM退出的时候销毁。而其他的数据依赖于每一个线程,在线程创建时创建,在线程退出时销毁。分别有程序计数器,堆,栈,方法区,运行时常量池 程序计数器:每个线程一旦被创建就拥有了自己的程序计数器。当线程执行Java方法的时候,它包含该线程正在被执行的指令的地址。但是若线程执行的是一个本地的方法,那么程序计数器的值就不会被定义。 常量缓冲池和方法区:常量缓冲池用于存储类名称、方法和字段名称以及串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方式。 栈:Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。每个栈框架包括以下三类信息: 局部变量:对应vars寄存器指向该变量表中的第一个局部变量,用于存储一个类的方法中所用到的局部变量。 执行环境:对应frame寄存器的当前执行环境指针,用于保存解释器对Java字节码进行解释过程中所需的信息。它们是:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。执行环境是一个执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。 操作数栈:对应optop寄存器的操作数栈顶指针,操作数栈用于存储运算所需操作数及运算的结果。 堆:JVM中最大的,应用的对象和数据都是存在这个区域,这块区域也是线程共享的,也是 gc 主要的回收区,一个 JVM 实例只存在一个堆类存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,以方便执行器执行。 垃圾回收机制(GC)只发生在线程共享区,也就是堆和方法区,栈不需要回收,线程销毁则栈也销毁, 也就是上图的heap space与method area会发生gc。 通过上图可以发现heap space被分为两部分: Young Generation:又分为Eden space所有的类都是在Eden space被new出来的。From区(Survivor 0 space)和To区(Survivor 1 space)。当Eden space空间用完时,程序又需要创建对象,JVM的垃圾回收器将对Eden space进行垃圾回收(Minor GC),将Eden space中的剩余对象移动到From区。若From区也满了,再对该区进行垃圾回收,然后移动到To区。那如果To区也满了呢,再移动到Old区。 Old Generation:若该区也满了,那么这个时候将产生Major GC(FullGCC),进行Tenured区的内存清理。若该区执行Full GC 之后发现依然无法进行对象的保存,产生异常java.lang.OutOfMemoryError: Java heap space。 Java虚拟机的堆内存设置不够,可以通过参数-Xms、-Xmx来调整。 代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)。 Permanent Generation:是一个常驻内存区域,用于存放JDK自身所携带的 Class,Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。产生异常java.lang.OutOfMemoryError: PermGen space jdk1.8之后已经不会再报报这个错误了。因为类信息的卸载几乎很少发生,这样会影响GC的效率。于是PermGen便被拆分出去了。 程序启动需要加载大量的第三方jar包。例如:在一个Tomcat下部署了太多的应用。 大量动态反射生成的类不断被加载,最终导致Perm区被占满。 jvm的算法 由于算法篇幅太长具体算法可自行查阅资料,主要介绍gc算法发生在什么区。 分代搜集算法:是由复制算法、标记/整理、标记/清除算法共同组成 复制算法发生在Young Generation 标记/整理和标记/清除算法发生在Old Generation和Permanent Generation java验证jvm 栈中一般存放的都是对象的指针和基本类型,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。 栈数据可以共享 /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args) { int a=0; int b=0; System.out.print(a==b); }} "C:Program FilesJavajdk1.8.0_151injava"trueProcess finished with exit code 0 编译器先处理int a = 0;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为0的地址,没找到,就开辟一个存放0这个字面值的地址,然后将a指向0的地址。接着处理int b = 0;在创建完b的引用变量后,由于在栈中已经有0这个字面值,便将b直接指向0的地址。这样,就出现了a与b同时均指向0的情况 /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args) { int a=0; int b=0; a=1; System.out.print("a="+a); System.out.print("b="+b); System.out.print(a==b); }} "C:Program FilesJavajdk1.8.0_151injava" a=1b=0falseProcess finished with exit code 0 再令a=1;那么,b不会等于1,还是等于0。在编译器内部,遇到a=1;时,它就会重新搜索栈中是否有1的字面值,如果没有,重新开辟地址存放1的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。 String str = "abc"的工作原理 /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args) { String str1 = "abc"; String str2 = "abc"; System.out.println(str1==str2); }} "C:Program FilesJavajdk1.8.0_151injava"trueProcess finished with exit code 0 /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args) { String str1 = "abc"; String str2 = "abc"; str1 = "bcd"; System.out.println(str1 + "," + str2); System.out.println(str1==str2); }} "C:Program FilesJavajdk1.8.0_151injava" bcd,abcfalseProcess finished with exit code 0 赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为"bcd"时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。 /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args) { String str1 = "abc"; String str2 = "abc"; str1 = "bcd"; String str3 = str1; System.out.println(str3); String str4 = "bcd"; System.out.println(str1 == str4); }} "C:Program FilesJavajdk1.8.0_151injava"bcdtrueProcess finished with exit code 0 str3这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用 str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。 堆验证 String类 /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args) { String str1 = new String("abc"); String str2 = "abc";System.out.println(str1==str2);}} "C:Program FilesJavajdk1.8.0_151injava"falseProcess finished with exit code 0 以上代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。 使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。这个思想应该是 享元模式的思想。 由于String类的性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。 执行时间上寄存器 < 堆栈 < 堆 /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args) { String s1 = "ja"; String s2 = "va"; String s3 = "java"; String s4 = s1 + s2; System.out.println(s3 == s4); System.out.println(s3.equals(s4)); }} "C:Program FilesJavajdk1.8.0_151injava"falsetrueProcess finished with exit code 0 是不是很矛盾啊!是不是又懵逼了? 打印false的原因是,java 重载了“+”,查看java字节码可以发现“+”其实是调用了StringBuilder 所以使用了“+”其实是生成了一个新的对象。所以(s3 == s4)打印false /*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args){ long maxMemory = Runtime.getRuntime().maxMemory();//返回Java虚拟机试图使用的最大内存量。 Long totalMemory = Runtime. getRuntime().totalMemory();//返回jvm实例占用的内存。 System.out.println("MAX_MEMORY ="+maxMemory +"(字节)、"+(maxMemory/(double)1024/1024) + "MB"); System.out.println("TOTAL_ MEMORY = "+totalMemory +"(字节)"+(totalMemory/(double)1024/1024) + "MB"); }} "C:Program FilesJavajdk1.8.0_151injava" -XX:+PrintGCDetailsMAX_MEMORY =1868038144(字节)、1781.5MBTOTAL_ MEMORY = 126877696(字节)121.0MBHeapPSYoungGen total 37888K, used 3932K [0x00000000d6400000, 0x00000000d8e00000, 0x0000000100000000) eden space 32768K, 12% used [0x00000000d6400000,0x00000000d67d7320,0x00000000d8400000) from space 5120K, 0% used [0x00000000d8900000,0x00000000d8900000,0x00000000d8e00000) to space 5120K, 0% used [0x00000000d8400000,0x00000000d8400000,0x00000000d8900000)ParOldGen total 86016K, used 0K [0x0000000082c00000, 0x0000000088000000, 0x00000000d6400000) object space 86016K, 0% used [0x0000000082c00000,0x0000000082c00000,0x0000000088000000)Metaspace used 3325K, capacity 4494K, committed 4864K, reserved 1056768K class space used 363K, capacity 386K, committed 512K, reserved 1048576KProcess finished with exit code 0 将jvm堆初始值改小,触发gc回收 import java.util.Random;/*** Created by liustc on 2018/4/20.*/public class JvmTest { public static void main(String[] args){ long maxMemory = Runtime.getRuntime().maxMemory();//返回jvm试图使用的最大内存量。 Long totalMemory = Runtime. getRuntime().totalMemory();//返回jvm实例的内存大小。 System.out.println("MAX_MEMORY ="+maxMemory +"(字节)、"+(maxMemory/(double)1024/1024) + "MB"); System.out.println("TOTAL_ MEMORY = "+totalMemory +"(字节)"+(totalMemory/(double)1024/1024) + "MB"); String str = "www.baidu.com"; while(true){ str += str + new Random().nextInt(88888888) + new Random().nextInt(99999999); } }} "C:Program FilesJavajdk1.8.0_151injava" -XX:+PrintGCDetailsMAX_MEMORY =1868038144(字节)、1781.5MBTOTAL_ MEMORY = 126877696(字节)121.0MB[GC (Allocation Failure) [PSYoungGen: 32247K->2729K(37888K)] 32247K->10124K(123904K), 0.0045031 secs] [Times: user=0.01 sys=0.03, real=0.00 secs][GC (Allocation Failure) [PSYoungGen: 32912K->4469K(70656K)] 40307K->26638K(156672K), 0.0121112 secs] [Times: user=0.00 sys=0.00, real=0.01 secs][GC (Allocation Failure) [PSYoungGen: 66160K->776K(70656K)] 88329K->59879K(156672K), 0.0141096 secs] [Times: user=0.03 sys=0.02, real=0.01 secs][Full GC (Ergonomics) [PSYoungGen: 776K->0K(70656K)] [ParOldGen: 59103K->37630K(116224K)] 59879K->37630K(186880K), [Metaspace: 3408K->3408K(1056768K)], 0.0143902 secs] [Times: user=0.03 sys=0.00, real=0.01 secs][Full GC (Ergonomics) [PSYoungGen: 60370K->0K(70656K)] [ParOldGen: 96726K->74565K(172032K)] 157096K->74565K(242688K), [Metaspace: 3409K->3409K(1056768K)], 0.0598124 secs] [Times: user=0.08 sys=0.00, real=0.06 secs][GC (Allocation Failure) [PSYoungGen: 60382K->32K(95744K)] 1257771K->1226968K(1463808K), 0.0227293 secs] [Times: user=0.06 sys=0.01, real=0.02 secs][GC (Allocation Failure) [PSYoungGen: 32K->32K(131584K)] 1226968K->1226968K(1499648K), 0.0037586 secs] [Times: user=0.00 sys=0.00, real=0.00 secs][Full GC (Allocation Failure) [PSYoungGen: 32K->0K(131584K)] [ParOldGen: 1226936K->355271K(483840K)] 1226968K->355271K(615424K), [Metaspace: 3409K->3409K(1056768K)], 0.1616835 secs] [Times: user=0.19 sys=0.09, real=0.16 secs][GC (Allocation Failure) [PSYoungGen: 2499K->32K(158208K)] 1303306K->1300838K(1526272K), 0.0037952 secs] [Times: user=0.06 sys=0.00, real=0.00 secs][GC (Allocation Failure) [PSYoungGen: 32K->32K(158208K)] 1300838K->1300838K(1526272K), 0.0036491 secs] [Times: user=0.00 sys=0.00, real=0.00 secs][Full GC (Allocation Failure) [PSYoungGen: 32K->0K(158208K)] [ParOldGen: 1300806K->473463K(622080K)] 1300838K->473463K(780288K), [Metaspace: 3409K->3409K(1056768K)], 0.1641897 secs] [Times: user=0.30 sys=0.06, real=0.16 secs][GC (Allocation Failure) [PSYoungGen: 0K->0K(250880K)] 946230K->946230K(1618944K), 0.0027229 secs] [Times: user=0.00 sys=0.00, real=0.00 secs][GC (Allocation Failure) [PSYoungGen: 0K->0K(258560K)] 946230K->946230K(1626624K), 0.0027747 secs] [Times: user=0.00 sys=0.00, real=0.00 secs][Full GC (Allocation Failure) [PSYoungGen: 0K->0K(258560K)] [ParOldGen: 946230K->709846K(879104K)] 946230K->709846K(1137664K), [Metaspace: 3409K->3409K(1056768K)], 0.1013768 secs] [Times: user=0.28 sys=0.02, real=0.10 secs][GC (Allocation Failure) [PSYoungGen: 0K->0K(353280K)] 709846K->709846K(1721344K), 0.0049384 secs] [Times: user=0.00 sys=0.00, real=0.01 secs][Full GC (Allocation Failure) Exception in thread "main" java.lang.OutOfMemoryError: Java heap space[PSYoungGen: 0K->0K(353280K)] [ParOldGen: 709846K->709816K(900608K)] 709846K->709816K(1253888K), [Metaspace: 3409K->3409K(1056768K)], 0.1792920 secs] [Times: user=0.39 sys=0.00, real=0.18 secs]Heapat java.util.Arrays.copyOf(Arrays.java:3332) PSYoungGen total 353280K, used 14028K [0x00000000d6400000, 0x00000000ec700000, 0x0000000100000000)at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124) eden space 352768K, 3% used [0x00000000d6400000,0x00000000d71b3070,0x00000000ebc80000)at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:674) from space 512K, 0% used [0x00000000ec680000,0x00000000ec680000,0x00000000ec700000)at java.lang.StringBuilder.append(StringBuilder.java:208) to space 4608K, 0% used [0x00000000ebe00000,0x00000000ebe00000,0x00000000ec280000)at JvmTest.main(JvmTest.java:15) ParOldGen total 1368064K, used 709816K [0x0000000082c00000, 0x00000000d6400000, 0x00000000d6400000)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) object space 1368064K, 51% used [0x0000000082c00000,0x00000000ae12e1e8,0x00000000d6400000) Metaspace used 3440K, capacity 4494K, committed 4864K, reserved 1056768Kat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) class space used 377K, capacity 386K, committed 512K, reserved 1048576Kat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)Process finished with exit code 1 欢迎工作一到五年的Java程序员朋友们加入Java架构开发:744677563 本群提供免费的学习指导 架构资料 以及免费的解答 不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导

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

Android TahHost的使用2 不继承TabActivity

Layout的设计,其实有我这里直接拖了一个TabHost控件,然后在每个Tab中放一个Button。 文件名为activity_tab_host.xml. <RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http://schemas.android.com/tools" android:layout_width= "match_parent" android:layout_height= "match_parent" android:paddingBottom= "@dimen/activity_vertical_margin" android:paddingLeft= "@dimen/activity_horizontal_margin" android:paddingRight= "@dimen/activity_horizontal_margin" android:paddingTop= "@dimen/activity_vertical_margin" tools:context= ".TabHostActivity" > <TabHost android:id= "@+id/tabhost" android:layout_width= "match_parent" android:layout_height= "match_parent" android:layout_alignParentLeft= "true" android:layout_alignParentTop= "true" > <LinearLayout android:layout_width= "match_parent" android:layout_height= "match_parent" android:orientation= "vertical" > <TabWidget android:id= "@android:id/tabs" android:layout_width= "match_parent" android:layout_height= "wrap_content" > </TabWidget> <FrameLayout android:id= "@android:id/tabcontent" android:layout_width= "match_parent" android:layout_height= "match_parent" > <LinearLayout android:id= "@+id/tab1" android:layout_width= "match_parent" android:layout_height= "match_parent" > <Button android:id= "@+id/button1" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "Fist Tab Content" /> </LinearLayout> <LinearLayout android:id= "@+id/tab2" android:layout_width= "match_parent" android:layout_height= "match_parent" > <Button android:id= "@+id/button1" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "Second Tab Content" /> </LinearLayout> <LinearLayout android:id= "@+id/tab3" android:layout_width= "match_parent" android:layout_height= "match_parent" > <Button android:id= "@+id/button1" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "Third Tab Content" /> </LinearLayout> </FrameLayout> </LinearLayout> </TabHost> </RelativeLayout> 需要注意的是TabHost必须包含一个 TabWidget和一个FrameLayout。而且TabWidget的id属性必须为 @android:id/tabs,FrameLayout的id属性必须为 @android:id/tabcontent。 下面TabHostActivity.java文件为: public class TabHostActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tab_host); TabHost tabHost = (TabHost)findViewById(R.id.tabhost); tabHost.setup(); tabHost.addTab(tabHost.newTabSpec( "tab1" ) .setIndicator( "First Tab" ) .setContent(R.id.tab1)); tabHost.addTab(tabHost.newTabSpec( "tab2" ) .setIndicator( "Second Tab" ) .setContent(R.id.tab2)); tabHost.addTab(tabHost.newTabSpec( "tab3" ) .setIndicator( "Third Tab" ) .setContent(R.id.tab3)); } } 效果图: 本文转自Work Hard Work Smart博客园博客,原文链接:http://www.cnblogs.com/linlf03/archive/2013/03/16/2963638.html,如需转载请自行联系原作者

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

构建GEO数据飞轮:从可见度监控到认知优化的闭环系统

GEO的核心价值不在于"测量",而在于"优化"。然而,多数企业的GEO实践停留在被动监控阶段——收集AI回答数据、生成报告、等待下一次变化。真正的GEO竞争力来自数据飞轮:每一次测量都触发优化动作,每一次优化又产生新的测量数据,形成自我强化的认知提升循环。本文从飞轮设计、工程实现、运营节奏三个层面,拆解如何构建一个可运转的GEO数据飞轮。

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

家政AI搜索可见性机制探究:从平台引用到获客链路

CNNIC 第 57 次报告显示,生成式 AI 用户中 40 岁以上占比半年提高 4.9 个百分点至 30.3%,家政服务的付费决策人恰好集中在这个年龄段。我实测豆包和 DeepSeek 的引用数据后发现,家政客户找服务商的路径已经从「打开 58 搜保洁」变成了「打开豆包问哪家靠谱」。你的客户在 AI 里找答案,你的获客动作还停留在地推和分类信息网站,这个错位就是获客越来越难的根本原因。

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

多租户舆情搜索的工程化交付:隔离、加速与证据可见性

企业落地舆情系统时,搜索体验往往比采集数量更早暴露架构问题。不同团队有不同的关键词、权限和数据保留要求;同一个查询可能需要跨文章、事件、来源和报告证据;高峰期的大范围检索又容易影响实时告警。若只在单一搜索接口上不断增加过滤条件,最终会出现慢查询、越权风险和无法解释的结果。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

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

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文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册