Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the JAVA performance design method?

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "what is the JAVA performance design method". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Summary

Many common Java performance problems originate from the idea of class design early in the design process, long before many developers start to think about performance issues. In this series, Brian Goetz discusses common Java performance adventures and how to avoid them at design time.

Many programmers consider performance management later in the development cycle. They often put off performance optimization until the end, hoping to avoid it altogether-sometimes the strategy is successful. But early design ideas can affect the requirements and success of performance optimization. If performance is an important indicator of your program, performance management should be integrated with setting the development cycle from day one.

This series explores ways in which early design ideas can greatly affect application performance. In this article, I focus on one of the most common performance issues: the creation of temporary variables. The way a class's objects are created is often determined at design time-- but not intentionally-- sowing the seeds for later performance problems.

Performance problems take various forms. The easiest to adjust are those that you simply choose the wrong algorithm for calculation-like using the Bubble algorithm to sort a big data set, or calculating every time instead of buffering a frequently used data item. You can use profile analysis to simply identify these bottlenecks, and once found, you can easily correct them. However, many Java performance problems come from a deeper and more difficult source of correction-the interface design of a program component.

Most programs today are built from internally developed or externally purchased components. Even when the program is not heavily dependent on existing components, the object-oriented design process encourages applications to be packaged as components, thus simplifying the design, development, and testing process. These advantages are undeniable, and you should realize that the interfaces implemented by these components can greatly affect the behavior and performance of programs that use them.

At this point, you may want to ask what kind of interface is related to performance. The interface of a class defines not only the functions that the class can implement, but also its object creation behavior and the sequence of method calls that use it. How a class defines its constructors and methods determines whether an object can be reused, whether its methods create-- or require its client to create-- intermediate objects, and how many methods a client needs to call to use the class. These factors will affect the performance of the program.

Pay attention to the creation of objects

One of the most basic Java performance management principles is to avoid a large number of object creation. This is not to say that you should give up the benefits of object orientation without creating any objects. But you must pay attention to the creation of objects in a tight loop when executing performance-related code. Object creation is so expensive that you should avoid unnecessary temporary or intermediate object creation when performance is required.

The String class is the main source of object creation in programs that process text. Because String is immutable, every time a String is modified or created, a new object must be created. As a result, performance-focused programs should avoid using a lot of String. However, this is usually impossible. Even when you completely remove the dependence on String from your code, you will often find yourself using components with interfaces defined according to String. So, you end up having to use String.

Example: regular expression matching

As an example, suppose you write a mail server called MailBot. MailBot needs to process the MIME header format-- like the date it was sent or the sender's email address-- at the top of each message. Use a component that matches regular expressions to make it easier to process MIME headers. MailBot is smart enough not to create a String object for each header row or header element. Instead, it fills a character buffer with input text and indexes the buffer to determine the position of the header to be processed. MailBot invokes the regular expression matcher to process each header line, so the performance of the matcher is very important. Let's take the poor interface of a regular expression matcher class as an example:

Public class AwfulRegExpMatcher {

/ * * Create a matcher with the given regular expression and which will

Operate on the given input string * /

Public AwfulRegExpMatcher (String regExp, String inputText)

/ * * Retrieve the next match of the pattern against the input text

Returning the matched text if possible or null if not * /

Public String getNextMatch ()

}

Even when this class implements an effective regular expression matching algorithm, any program that uses it heavily is still unbearable. Now that the matcher object is associated with the input text, every time you call it, you must create a new matcher object. Since your goal is to reduce unnecessary object creation, making this matcher accessible would be an obvious start.

The following class definition demonstrates another possible interface for your matcher, which allows you to reuse the matcher, but it's still bad.

Public class BadRegExpMatcher {

Public BadRegExpMatcher (String regExp)

/ * * Attempts to match the specified regular expression against the input

Text, returning the matched text if possible or null if not * /

Public String match (String inputText)

/ * * Get the next match against the input text, or return null if no match * /

Public String getNextMatch ()

}

What's wrong with this seemingly harmless class definition by ignoring the details of regular expression matching-like returning matching subexpressions? Functionally, no. But from a performance point of view, many. First, the matcher requires its caller to create a String to represent the text to match. MailBot tries to avoid creating String objects, but when it wants to find a header to do regular expression parsing, it has to create a String to satisfy BadRegExpMatcher:

BadRegExpMatcher dateMatcher = new BadRegExpMatcher (...)

While (...) {

...

String headerLine = new String (myBuffer, thisHeaderStart

ThisHeaderEnd-thisHeaderStart)

String result = dateMatcher.match (headerLine)

If (result = = null) {...}

}

Second, the matcher creates the result string even when MailBot only cares about matching and does not need matching text, which means that to simply use BadRegExpMatcher to confirm whether a date header matches a particular format, you must create two String objects-the input of the matcher and the matching result. Two objects may not seem like much, but if you create two objects for each header line of every message processed by MailBot, it will greatly affect performance. The fault lies not in the design of MailBot, but in the design of the BadRegExpMatcher class-or the use of it.

Note that returning a lightweight Match object-- which can provide getOffset (), getLength (), egetMatchString () methods-- instead of returning a String, does not greatly improve performance. Because creating a Match object may be less expensive than creating a String-- including generating a char [] array and copying data, you still create an intermediate object that is of no value to your caller.

This is bad enough that BadREgExpMatcher forces you to use the input form it wants to see, rather than the more efficient form you can provide. But there is another danger to using BadRegExpMathcer, which potentially poses a bigger risk to MailBot performance: you have a tendency to avoid using String when dealing with headers. But since you are forced to create many String objects to satisfy BadRegExpMatcher, you may be tempted to give up this goal and use String more freely. Now, the poor design of a component has affected the programs that use it.

Even if you later find a better regular expression component, you don't need to provide a String, and your whole program will be affected.

A better interface

How do you define BadRegExpMatcher without causing such a problem? First of all, BadRegExpMatcher should not specify its input. It should be able to accept various input formats that its callers can effectively provide. Second, it should not automatically generate a String; for the matching result. It should return enough information so that the caller can generate it if desired. (for convenience, it can provide a way to do this, but not necessary.) here is a better interface:

Class BetterRegExpMatcher {

Public BetterRegExpMatcher (...)

/ * * Provide matchers for multiple formats of input-String

Character array, and subset of character array. Return-1 if no

Match was made; return offset of match start if a match was

Made. , /

Public int match (String inputText)

Public int match (char [] inputText)

Public int match (char [] inputText, int offset, int length)

/ * * Get the next match against the input text, if any * /

Public int getNextMatch ()

/ * * If a match was made, returns the length of the match; between

The offset and the length, the caller should be able to

Reconstruct the match text from the offset and length * /

Public int getMatchLength ()

/ * * Convenience routine to get the match string, in the event the

Caller happens to wants a String * /

Public String getMatchText ()

}

The new interface reduces the requirement for the caller to convert the input to the format desired by the matcher. MailBot can now call match () as follows:

Int resultOffset = dateMatcher.match (myBuffer, thisHeaderStart

ThisHeaderEnd-thisHeaderStart)

If (resultOffset < 0) {...}

This solves the goal of not creating any new objects. As an additional bonus, its interface design style is added to Java's "lots-of-simgle-methos" design philosophy.

The exact impact of additional object creation on performance depends on the amount of work done by matth (). You can determine an upper limit for performance differences by creating and timing two regular expression matcher classes. In Sun JDK 1.3, the above code snippet is about 50 times faster in the BetterRegExpMatcher class than in the BadRegExpMatcher class. Using a simple implementation of string matching, BetterRegExpMatcher is five times faster than its BadRegExpMatcher counterpart.

Exchange type

BadRegExpMatcher forces MailBot to convert input text from a character array to String, resulting in unnecessary object creation. More ironically, many implementations of BadRegExpMatcher immediately convert String into an array of characters, making it easy to access input text. This not only applies for another elephant, but also means that you have done all the work in the same form as at the beginning. Neither MailBot nor BadRegExpMatcher wants to deal with String-String just looks like an obvious format for passing text between components.

In the BadRegExpMatcher example above, the String class is used as an exchange type. An exchange type is a type that neither the caller nor the callee wants to use or use as a data format, but both can be easily converted or converted from it. Defining interfaces by exchange types reduces the complexity of interfaces while maintaining flexibility, but sometimes simplicity leads to costly performance.

The most typical example of a switching type is the JDBC ResultSet interface. It is impossible to provide its ResultSet interface like any dataset provided by a local database, but the JDBC driver can easily package the local data representation provided by the database by implementing a ResultSet. Similarly, client programs can't represent data records like this, but you can convert ResultSet into the desired data representation almost without difficulty. In JDBC's case, you accept this level of cost because it brings the benefits of standardization and portability across database implementations. However, pay attention to the performance cost of switching types.

It's not worth it at all, and the performance impact of using swap types is not easy to measure. If you test the above code snippet that calls BadRegExpMatcher, it creates an input String; for MailBot at run time, but String is generated only to satisfy BadRegExpMatcher. If you want to assess the real impact of a component on program performance, you should measure not only the resource usage of its code, but also the code that uses it and recovers. This is difficult to accomplish for standard testing tools.

This is the end of the content of "what is the JAVA performance Design method?" Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report