简体   繁体   English

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

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

I have some questions about performances for those kind of stations (using Spring Boot for my project now). 我对这类工作站的性能有一些疑问(现在将Spring Boot用于我的项目)。 As you will understand soon, I'm a bit confused while learning lots of informations at once. 如您很快就会了解的那样,我在一次学习大量信息时有些困惑。 So i will share my different kind of questions and some of my tests to understand the flow and help others who are confused like me: 因此,我将分享我不同类型的问题和一些测试,以了解流程并帮助像我这样困惑的其他人:

1) Reading application.properties like this: 1)读取application.properties像这样:

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

vs reading properties starting with poo into the class and getting its value with getters. 与从poo开始向类读取属性并通过getter获得其价值。

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

   // setters and getters
}

1a) So which approach is faster and why? 1a)那么哪种方法更快,为什么呢? Can you explain it with memory performances if there is a difference 1b) Also lets say i use FooBean approach and in the Example1 class i need only FooBean's name. 如果存在差异,可以用内存性能来解释吗?1b)也可以说我使用FooBean方法,在Example1类中,我只需要FooBean的名称。 Should i inject FooBean to the Example1 class while i need only 1 field of it or should i use @Value style and get only specific field, which has better performance now? 我应该在只需要1个字段的同时将FooBean注入到Example1类中还是应该使用@Value样式并仅获取特定的字段,该字段现在具有更好的性能?

2) Should i declare fields of FooBean as static? 2)我应该将FooBean的字段声明为静态的吗? Lets see an example: 让我们来看一个例子:

Configuration class: 配置类:

@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;
}

And lets say this class only will be used by its Service: 并且可以说此类仅由其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();
    }

If i am correct the scenario will be like this: 如果我是正确的,情况将是这样的:

1) In this case I will be injecting those configurations as instance. 1)在这种情况下,我将注入那些配置作为实例。 2) So every class (lets say i have 10.000 users in a minute and this class will be created 10.000 times) will create their own configuration in the stack, will it and when it completes, deletes it, so memory is free again. 2)因此,每个类(假设我在一分钟内有10.000个用户,并且该类将被创建10.000次)将在堆栈中创建自己的配置,将其创建,并在完成后将其删除,因此可以再次释放内存。 3) But because there will be so many request, doesn't it make memory problems? 3)但是因为会有很多请求,这是否会导致内存问题?

If this flow is correct, than should i create OpenStackBean's field as static and inject it as private static OpenStackBean ? 如果此流程正确,那我应该将OpenStackBean的字段创建为静态字段并将其作为private static OpenStackBean注入吗? This will be hold in the heap once and all users will get it from there. 它将被保存在堆中一次,所有用户将从那里获取它。 Which performance is better? 哪个性能更好?

3) Here is my some test results which makes me start thinking about String manipulations' and injection's performance. 3)这是我的一些测试结果,这使我开始考虑字符串操作和注入的性能。 Here is sample stress test using JMeter and visualizing with Java VisualVM 这是使用JMeter进行压力测试的示例,并使用Java VisualVM进行可视化

测试前

Sending 10.000 requests 发送10.000个请求

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

But i don't understand why heap usage always increases. 但是我不明白为什么堆使用总是增加。 Here is how APP works: 这是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);
            }

All requests entered this condition and called: 所有请求都进入此条件,并调用:

2) This function is called. 2)调用此函数。 Since categorizedGameList is static (which is initializied on the APP startup, and will be updated from the remote server daily by a Scheduler), all requests directly return with 2 steps. 由于categorizedGameList是静态的(在APP启动时初始化,并且将由Scheduler每天从远程服务器进行更新),因此所有请求都将直接返回2个步骤。 GameList is in the Heap, so no new instance will be created. GameList位于堆中,因此不会创建新实例。

GameList --> 14 KB (14173 byte) GameList-> 14 KB(14173字节)

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

3) So why heap increases 300MB (from 100 to 400) after 10000 requests? 3)那么为什么在10000个请求后,堆会增加300MB(从100增加到400)? This means 30 KB is created in the memory for every requests. 这意味着将为每个请求在内存中创建30 KB。

3a) What exactly happens when a request comes to an endpoint? 3a)当请求到达端点时会发生什么? Are all instance variables of the APP will be created or only visited classes will be created? 是否将创建APP的所有实例变量,或者仅创建访问的类? I was thinking like this: 我当时是这样想的:

  • User creates a connection to my endpoint 用户创建到我的端点的连接
  • User will be routed to my Controller class, so this class is created in the memory. 用户将被路由到我的Controller类,因此该类在内存中创建。 (Not all the classes of the application). (不是应用程序的所有类)。 Its instance variables is created for this user only, static fields will be served from the memory for all users. 它的实例变量仅为此用户创建,静态字段将为所有用户从内存中提供。
  • Controller's Service is called. 调用控制器的服务。 So this Service is created for this user too. 因此,该服务也是为此用户创建的。
  • Return static list to this user. 返回静态列表给该用户。 This will not increase my memory 14KB, because it is already in the heap. 这不会增加我的内存14KB,因为它已经在堆中了。
  • But my memory is increasing 30 KB for each request. 但是每个请求的内存增加了30 KB。

I know this is too long for read but i tried to give all my experiences during this path. 我知道这太长了,无法阅读,但我尝试在此过程中提供所有经验。 I'm a bit confused about improving my performance, since i realized that i have never thought about it. 我对提高性能有些困惑,因为我意识到自己从未考虑过。 Thanks for your patience. 谢谢你的耐心。

  1. In this case I will be injecting those configurations as instance. 在这种情况下,我将注入这些配置作为实例。 2) So every class (lets say i have 10.000 users in a minute and this class will be created 10.000 times) will create their own configuration in the stack, will it and when it completes, deletes it, so memory is free again. 2)因此,每个类(假设我在一分钟内有10.000个用户,并且该类将被创建10.000次)将在堆栈中创建自己的配置,将其创建,并在完成后将其删除,因此可以再次释放内存。 3) But because there will be so many request, doesn't it make memory problems? 3)但是因为会有很多请求,这是否会导致内存问题?

No it will not be a problem. 不,这不是问题。 Spring beans are by default "Singleton" scope (except you explicitly set another scope), so only one instance of OpenStackBean will be created. 默认情况下,Spring Bean是“ Singleton”作用域(除非您显式设置了另一个作用域),因此将仅创建一个OpenStackBean实例。 So there is no need to create static field. 因此,无需创建静态字段。

So why heap increases 300MB (from 100 to 400) after 10000 requests? 那么,为什么在10000个请求后堆增加300MB(从100到400)? This means 30 KB is created in the memory for every requests. 这意味着将为每个请求在内存中创建30 KB。

Because tomcat need to create many temporary objects to handle the request, but they will be gone after request have been served (Also note that you won't see decrease in heap usage because java only remove unused objects after Garbage collection) 因为tomcat需要创建许多临时对象来处理请求,但是在处理完请求后它们将消失(还请注意,由于Java仅在垃圾回收之后才删除未使用的对象,因此堆使用率不会降低)

Controller's Service is called. 调用控制器的服务。 So this Service is created for this user too. 因此,该服务也是为此用户创建的。

That's also false, if your controller is Singletone scope, it's created only once. 这也是错误的,如果您的控制器是Singletone作用域,则仅创建一次。

What exactly happens when a request comes to an endpoint? 当请求到达端点时,究竟发生了什么? Are all instance variables of the APP will be created or only visited classes will be created? 是否将创建APP的所有实例变量,或者仅创建访问的类?

Of curse not! 不骂人的! when tomcat serve your request, only required calsses need to be instantiated. 当tomcat服务您的请求时,仅需要实例化cals。

In general, you are over concerning about performance issues. 总的来说,您对性能问题的关注已经结束。 the thing that you should be concerned is when an object is not removed from memory (Memory usage increased and not decreased after GC untill application crash). 您应该关注的事情是何时未从内存中删除对象(GC使用直到应用程序崩溃后,内存使用量增加且没有减少)。 Also concerning memory footprint is real, but not about a few small objects created and destroyed through minor GCs. 同样涉及内存占用是真实的,但与通过次要GC创建和销毁的一些小对象无关。

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

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