关于【禁止new对象时在for循环内定义申明变量】

文章目录

  • 简介
  • 代码分析
  • 反编译之后对比
  • 性能测试
  • 内存与垃圾回收情况
  • JDK和常用框架怎么写
  • 总结
  • 依赖

简介

不知道是谁最先提出了一个不要将变量定义在循环内。

然后我们在代码扫描中有一项是:【禁止new对象时在for循环内定义申明变量】

我也好奇为什么不能?

是影响了性能?还是影响了内存?还是影响了垃圾回收?

我们站在制定这条规则的人的角度来想一想可能的原因:

  1. 变量定义在for循环内,每次都要为变量引用分配空间,效率低
  2. 变量定义在for循环内,有引用,不利于内存回收

真的如此吗?我们先从代码分析一下。

代码分析

我们先从代码的角度分析,局部变量定义在循环外和循环内的区别。

不熟悉局部变量和字节码的朋友可以先看一看:
JVM字节码与局部变量

示例代码如下:

import java.util.HashMap;
import java.util.Map;public class Main {private static final int limit = 1000_0000;public static void main(String[] args) {}public void out() {Map<String, String> base;for (int i = 0; i < limit; i++) {base = new HashMap<>();base.put("1", "哦啊好");System.out.println(base);}}public void in() {for (int i = 0; i < limit; i++) {Map<String, String> base = new HashMap<>();base.put("1", "哦啊好");System.out.println(base);}}
}

我们可以:

# 编译class
javac Main.java# 查看字节码
javap -v Main.class

在这里插入图片描述

我们可以看到,无论变量定义在循环外还是循环内,base变量在局部变量表都只占据了一个slot。

自然,也就没有每次循环都要给变量引用分配空间的问题。至于base堆上的内存空间,无论变量定义在循环内外,肯定都要分配,没有区别。

至于垃圾回收,无论变量base在循环内还是循环外,局部变量base引用的都是最新new出来的Map对象,旧的对象不被引用,自然可以被回收,一点也不影响。

基本一模一样,不信我吗可以看看反编译之后的代码。

反编译之后对比

//
// Source code recreated from a .class file
// (powered by FernFlower decompiler)
//package vip.meet;import java.util.HashMap;
import java.util.Map;public class Main {private static final int limit = 10000000;public Main() {}public static void main(String[] args) {}public void out() {for(int i = 0; i < 10000000; ++i) {Map<String, String> base = new HashMap();base.put("1", "哦啊好");System.out.println(base);}}public void in() {for(int i = 0; i < 10000000; ++i) {Map<String, String> base = new HashMap();base.put("1", "哦啊好");System.out.println(base);}}
}

我们可以看到反编译之后,out方法的变量被放在循环中了,变得和in一模一样了。

有朋友肯能说,我看到了,他们字节码不一样啊,反编译出来的代码不能说明什么。

把out稍微改一下,将int i定义放在Map的base之前,字节码就一样了。

public void out() {int i = 0;Map<String, String> base;for (; i < limit; i++) {base = new HashMap<>();base.put("1", "哦啊好");System.out.println(base);}
}

如果,还觉得有疑问,我们下面来做点性能测试。

性能测试

我们先用benchmark做一些性能测试:

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;import java.util.HashMap;
import java.util.Map;public class BenchmarkLocalVarTest {private static final int limit = 10000_0000;@Benchmarkpublic void out() {Map<String, String> base;for (int i = 0; i < limit; i++) {base = new HashMap<>();base.put("1", "哦啊好");}}@Benchmarkpublic void in() {for (int i = 0; i < limit; i++) {Map<String, String> base = new HashMap<>();base.put("1", "哦啊好");}}public static void main(String[] args) throws RunnerException {Options options = new OptionsBuilder().include(BenchmarkLocalVarTest.class.getSimpleName()).forks(1).timeout(TimeValue.seconds(10)).threads(1).warmupIterations(1).warmupTime(TimeValue.seconds(10)).measurementTime(TimeValue.seconds(2)).measurementIterations(5).build();new Runner(options).run();}
}
Benchmark                   Mode  Cnt  Score   Error  Units
BenchmarkLocalVarTest.in   thrpt    5  0.349 ± 0.037  ops/s
BenchmarkLocalVarTest.out  thrpt    5  0.335 ± 0.039  ops/s

如果还有朋友觉得这个测试只能说明性能,不能看出内存和垃圾回收,那我们在来看一下内存和垃圾回收。

内存与垃圾回收情况

变量定义在循环内gc情况:
变量定义在循环内gc情况
变量定义在循环内内存情况:
变量定义在循环内内存情况
变量定义在循环外gc情况:
变量定义在循环外gc情况
变量定义在循环外内存情况:
变量定义在循环外内存情况
我们可以看到,没有太大区别,如果觉得上面逻辑太简单,可以自己试一下更复杂的情况。

JDK和常用框架怎么写

如果这样还不放心,那我们再看一下其他大神怎么写的:

JDK LinkedBlockingDeque:
JDK-LinkedBlockingDeque

Spring ResourceUrlProvider:
Spring-ResourceUrlProvider
apache io FileUtils:
apache io FileUtils

guava Files:
guava Files

总结

综上所述,【禁止new对象时在for循环内定义申明变量】并没有什么意义。

甚至,还带来了负面效果:

  1. 让变量作用域变大,存在被无意引用的风险
  2. 更容易产生变量名冲突
  3. 可读性变差

依赖

<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-core</artifactId><version>1.36</version><scope>test</scope>
</dependency>
<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-annprocess</artifactId><version>1.36</version>
</dependency>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/423619.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何利用MES系统进行产品质量全流程追溯

利用MES&#xff08;制造执行系统&#xff09;系统进行产品质量全流程追溯&#xff0c;是一个系统化和精细化的过程&#xff0c;主要涉及数据采集、信息整合、过程控制、查询分析以及持续优化等多个环节。以下是如何具体利用MES系统进行产品质量全流程追溯的步骤&#xff1a; 一…

centos(在线、离线)安装iptables

Iptables 是 Linux 操作系统中的一个用户空间工具&#xff0c;用来配置 Linux 内核中的 Netfilter 防火墙模块。它主要负责网络数据包的过滤、网络地址转换 (NAT) 以及配置防火墙规则。centos默认的防火墙管理工具是Firewalld&#xff0c;所以iptables需要下载安装。 目录 一…

嵌入式软件工程师:科技浪潮中的关键角色

嵌入式软件工程师&#xff1a;科技浪潮中的关键角色 一、嵌入式软件工程师的职业魅力 &#xff08;一&#xff09;市场需求旺盛 嵌入式软件工程师在当今科技领域中扮演着至关重要的角色。随着智能化时代的到来&#xff0c;嵌入式系统在各个行业的应用越来越广泛&#xff0c;市…

【贪心算法】贪心算法

贪心算法简介 1.什么是贪心算法2.贪心算法的特点3.学习贪心的方向 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.什么是贪心算法 与其说是…

[linux基础知识]教你使用vim和ctags阅读linux内核源码

1 安装ctags apt install ctags 2 内核源码目录下添加索引 使用下面命令&#xff0c;添加索引成功后&#xff0c;内核目录下会生成tags 索引文件。 ctags -R 3 vim使用索引阅读源码 跳转到函数变量定义与返回 #跳到函数或者变量定义 Ctrl] #返回 Ctrlo 光标移动到需要…

vue + Element UI table动态合并单元格

一、功能需求 1、根据名称相同的合并工作阶段和主要任务合并这两列&#xff0c;但主要任务内容一样&#xff0c;但要考虑主要任务一样&#xff0c;但工作阶段不一样的情况。&#xff08;枞向合并&#xff09; 2、落实情况里的定量内容和定性内容值一样则合并。&#xff08;横向…

设置使用阿里云服务器DNS

由于云服务器是从腾讯云迁移到阿里云&#xff0c;然后使用ssl验证时一直无法使用dns验证&#xff0c;也无法创建三级域名&#xff0c;原来需要把阿里云服务器改成阿里云的dns使用 如果使用其他服务器DNS会下面会显示当前DNS服务器&#xff0c;

Linux:git

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《Linux&#xff1a;git》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff01;&#xff01;&…

解决Docker镜像不可下载

使用国内可信的镜像中心 可信国内镜像网址&#xff1a;https://hub.atomgit.com/ 点击镜像仓库 搜索想要的镜像 按如图所示&#xff0c;即可查看对应的版本 点击复制&#xff0c;即可下载使用 缺点&#xff1a; 可用的镜像相比于docker官方量少 并且&#xff0c;获取的镜像名字…

【Java】方法2_Java的参数传递机制

文章目录 前言一、Java的参数传递机制都是值传递 1.基本类型的参数传递2.引用类型的参数传递总结 前言 学习Java的参数传递机制&#xff0c;基本类型的参数传递&#xff0c;引用类型的参数传递。 一、Java的参数传递机制都是值传递 值传递&#xff1a;指传输实参给方法的形参…

『功能项目』单例模式框架【37】

我们打开上一篇36C#拓展 - 优化冗余脚本的项目&#xff0c; 本章要做的事情是编写单例模式基类&#xff0c;让继承其基类的子类在运行时只存在一个&#xff0c;共有两个单例基类框架&#xff0c;分别是不继承MonoBehaviour的单例和继承MonoBehaviour的单例框架 首先编写不继承…

OpengGL教程(三)---使用VAO和VBO方式绘制三角形

本章参考官方教程&#xff1a;learnopengl-cn VertexShader.glsl #version 330 core layout(location 0) in vec3 position; layout(location 1) in vec3 color; uniform mat4 projection; // 投影矩阵 out vec4 ourColor; void main() {gl_Position projection * vec4(p…

Probabilistic Embeddings for Cross-Modal Retrieval 论文阅读

Probabilistic Embeddings for Cross-Modal Retrieval 论文阅读 Abstract1. Introduction2. Related work3. Method3.1. Building blocks for PCME3.1.1 Joint visual-textual embeddings3.1.2 Probabilistic embeddings for a single modality 3.2. Probabilistic cross-modal…

Xcode 16 RC (16A242) 发布下载,正式版下周公布

Xcode 16 RC (16A242) - Apple 平台 IDE IDE for iOS/iPadOS/macOS/watchOS/tvOS/visonOS 请访问原文链接&#xff1a;https://sysin.org/blog/apple-xcode-16/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Xcode 16 的新功…

开源项目低代码表单FormCreate中通过接口加载远程数据选项

在开源项目低代码表单 FormCreate 中&#xff0c;fetch 属性提供了强大的功能&#xff0c;允许从远程 API 加载数据并将其应用到表单组件中。通过灵活的配置&#xff0c;fetch 可以在多种场景下发挥作用&#xff0c;从简单的选项加载到复杂的动态数据处理。 源码地址: Github …

软考中项(第三版) 项目成本管理总结

前言 系统集成项目管理工程师考试&#xff08;简称软考中项&#xff09;&#xff0c;其中案例分析也是很大一部分考试内容&#xff0c;目前正在学习中&#xff0c;现总结一些可能会考到的知识点供大家参考。 1.1、项目成本管理总线索 1、项目成本失控的原因 &#xff08;1&a…

每日处理250亿个事件,Canva如何应对数据洪流

在这个数据被称为“新石油”的时代&#xff0c;如何有效地处理海量信息流显得尤为重要。作为广受欢迎的设计平台&#xff0c;Canva不仅因其用户友好的界面而备受关注&#xff0c;还因其高效利用Amazon Kinesis管理每日高达250亿个事件而成为热议焦点。让我们深入探讨Canva是如何…

Java 算法:随机抽题

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

W外链怎么做微信推广链接?

"W外链"通常指的是一种可以创建短链接或者特殊功能的链接服务&#xff0c;这些链接可以用来在微信等社交平台上进行推广。由于微信对直接链接分享有一定的限制&#xff0c;使用这类服务可以帮助绕过这些限制&#xff0c;从而实现更有效的推广。 以下是使用W外链创建微…

Mysql JSON结果不能IN

开发中遇到这样一种场景&#xff0c;举例说音乐的专辑包含歌曲&#xff0c;假设歌曲放在music表&#xff0c;专辑放在album表&#xff0c;而专辑与歌曲的绑定关系&#xff0c;要么就存一个关联表music_ablum&#xff0c;要么就存一个json字段(music_list)在album表。 存一个关…