繁体   English   中英

如何改善Java APP以获得更好的性能?

[英]How to improve my Java APP for better performance?

我对这类工作站的性能有一些疑问(现在将Spring Boot用于我的项目)。 如您很快就会了解的那样,我在一次学习大量信息时有些困惑。 因此,我将分享我不同类型的问题和一些测试,以了解流程并帮助像我这样困惑的其他人:

1)读取application.properties像这样:

@Value("${foo.name}")
private String name;

与从poo开始向类读取属性并通过getter获得其价值。

@ConfigurationProperties(prefix = "foo")
public class FooBean {
   private String name;
   private String age;
   ...

   // setters and getters
}

1a)那么哪种方法更快,为什么呢? 如果存在差异,可以用内存性能来解释吗?1b)也可以说我使用FooBean方法,在Example1类中,我只需要FooBean的名称。 我应该在只需要1个字段的同时将FooBean注入到Example1类中还是应该使用@Value样式并仅获取特定的字段,该字段现在具有更好的性能?

2)我应该将FooBean的字段声明为静态的吗? 让我们来看一个例子:

配置类:

@Component
@ConfigurationProperties(prefix = "openstack")
@Data
@Validated
public class OpenStackBean {

    @NotNull
    @Valid
    private String container;

    @NotNull
    @Valid
    private String keystoneEndpoint;

    @NotNull
    @Valid
    private String password;

    @NotNull
    @Valid
    private String swiftEndpoint;

    @NotNull
    @Valid
    private String tenantName;

    @NotNull
    @Valid
    private String userName;
}

并且可以说此类仅由其Service使用:

@Service
public class OpenStackService implements IOpenStackService {

    private OpenStackBean openStackBean;

    @Autowired
    public OpenStackService(OpenStackBean openStackBean) {
        this.openStackBean = openStackBean;
    }

...
...


private OSClientV2 authenticate(Facing perspective) throws AuthenticationException {
        return OSFactory
                .builderV2()
                .endpoint(openStackBean.getKeystoneEndpoint())
                .credentials(openStackBean.getUserName(), blowfish.decryptString(openStackBean.getPassword()))
                .tenantName(openStackBean.getTenantName())
                .perspective(perspective)
                .withConfig(Config
                        .newConfig()
                        .withConnectionTimeout(applicationBean.getConnectionTimeout())
                        .withReadTimeout(applicationBean.getReadTimeout())
                        .withMaxConnections(10)
                        .withMaxConnectionsPerRoute(2))
                .authenticate();
    }

如果我是正确的,情况将是这样的:

1)在这种情况下,我将注入那些配置作为实例。 2)因此,每个类(假设我在一分钟内有10.000个用户,并且该类将被创建10.000次)将在堆栈中创建自己的配置,将其创建,并在完成后将其删除,因此可以再次释放内存。 3)但是因为会有很多请求,这是否会导致内存问题?

如果此流程正确,那我应该将OpenStackBean的字段创建为静态字段并将其作为private static OpenStackBean注入吗? 它将被保存在堆中一次,所有用户将从那里获取它。 哪个性能更好?

3)这是我的一些测试结果,这使我开始考虑字符串操作和注入的性能。 这是使用JMeter进行压力测试的示例,并使用Java VisualVM进行可视化

测试前

发送10.000个请求

测试后-报告1测试后-报告2测试后-报告3

但是我不明白为什么堆使用总是增加。 这是APP的工作方式:

@RequestMapping(method = RequestMethod.GET)
    public ResponseEntity all(@ApiIgnore GameParam param) {
        try {
            // get games by categories by default
            if (param.getPageNo() == null) {
                return new ResponseEntity<>(gameService.getGamesByCategories(), HttpStatus.OK);
            }

所有请求都进入此条件,并调用:

2)调用此函数。 由于categorizedGameList是静态的(在APP启动时初始化,并且将由Scheduler每天从远程服务器进行更新),因此所有请求都将直接返回2个步骤。 GameList位于堆中,因此不会创建新实例。

GameList-> 14 KB(14173字节)

@Override
    public List<CategoryVO> getGamesByCategories() {
        if (categorizedGameList != null) {
            return categorizedGameList;
        } else {
            return getAndCategorizeGames();
        }
    }

3)那么为什么在10000个请求后,堆会增加300MB(从100增加到400)? 这意味着将为每个请求在内存中创建30 KB。

3a)当请求到达端点时会发生什么? 是否将创建APP的所有实例变量,或者仅创建访问的类? 我当时是这样想的:

  • 用户创建到我的端点的连接
  • 用户将被路由到我的Controller类,因此该类在内存中创建。 (不是应用程序的所有类)。 它的实例变量仅为此用户创建,静态字段将为所有用户从内存中提供。
  • 调用控制器的服务。 因此,该服务也是为此用户创建的。
  • 返回静态列表给该用户。 这不会增加我的内存14KB,因为它已经在堆中了。
  • 但是每个请求的内存增加了30 KB。

我知道这太长了,无法阅读,但我尝试在此过程中提供所有经验。 我对提高性能有些困惑,因为我意识到自己从未考虑过。 谢谢你的耐心。

  1. 在这种情况下,我将注入这些配置作为实例。 2)因此,每个类(假设我在一分钟内有10.000个用户,并且该类将被创建10.000次)将在堆栈中创建自己的配置,将其创建,并在完成后将其删除,因此可以再次释放内存。 3)但是因为会有很多请求,这是否会导致内存问题?

不,这不是问题。 默认情况下,Spring Bean是“ Singleton”作用域(除非您显式设置了另一个作用域),因此将仅创建一个OpenStackBean实例。 因此,无需创建静态字段。

那么,为什么在10000个请求后堆增加300MB(从100到400)? 这意味着将为每个请求在内存中创建30 KB。

因为tomcat需要创建许多临时对象来处理请求,但是在处理完请求后它们将消失(还请注意,由于Java仅在垃圾回收之后才删除未使用的对象,因此堆使用率不会降低)

调用控制器的服务。 因此,该服务也是为此用户创建的。

这也是错误的,如果您的控制器是Singletone作用域,则仅创建一次。

当请求到达端点时,究竟发生了什么? 是否将创建APP的所有实例变量,或者仅创建访问的类?

不骂人的! 当tomcat服务您的请求时,仅需要实例化cals。

总的来说,您对性能问题的关注已经结束。 您应该关注的事情是何时未从内存中删除对象(GC使用直到应用程序崩溃后,内存使用量增加且没有减少)。 同样涉及内存占用是真实的,但与通过次要GC创建和销毁的一些小对象无关。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM