In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces the example analysis designed for the performance of JAVA, which is very detailed and has a certain reference value. Interested friends must read it!
Part I: interface matters
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.
Conclusion
Not all programs focus on performance, not all programs have performance problems. But for those who pay attention to these programs, what is mentioned in this article is important because they cannot be modified at the last minute. Since it is difficult to modify the interface of a class after you write code to use it, spend a little extra time thinking about performance features during your design time.
In the second part, I will demonstrate some methods of using modifiable and unmodifiable to reduce unnecessary object creation.
Part II: reduce object creation
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. In the second part, he discusses some techniques for reducing the creation of temporary objects.
Although many programmers defer performance management until the end of the development process, performance considerations should be combined with the design cycle from day one. This series explores ways in which early design ideas can greatly affect application performance. In this article, I continue to explore the problems of creating a large number of temporary objects and provide some techniques to avoid them.
Temporary objects are objects with a short life cycle, which are generally used to store other data and for no other purpose. Programmers usually use temporary variables to pass data to or return data from a method. The first part discusses how temporary objects have a negative impact on the performance of a program, and how the design ideas of some class interfaces provide the creation of temporary objects. By avoiding the creation of those interfaces, you can greatly reduce the need for temporary object creation that affects the performance of your program
Just say no to String?
When it comes to creating temporary variables, the String class is one of the biggest sinners. To demonstrate, in the first part I wrote an example of regular expression matching that demonstrates how a seemingly harmless interface can cause a large number of objects to be created several times slower by comparing it with a similar but carefully designed interface. Here is the interface for the original and better classes:
BadRegExpMatcher
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)
}
BetterRegExpMatcher
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)
/ * * 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 ()
}
Programs that use a lot of BadREgExpMatcher are much slower than those that use BtterRegExpMatcher. First, the caller has to create a String to pass in match (), and then match () creates a String to return matching text. The result is that two objects are created for each call, which doesn't seem like much, but if match () is called frequently, these object creation costs too much performance. The performance problem of BadRegExpMatcher is not in its implementation, but in its interface; like the interface it defines, there is no way to avoid the creation of some temporary variables.
BetterRegExpMatcher's match () replaces the String object with the original type (integer and character array); there is no need to create intermediate objects to pass information between the caller and match ().
Since it is easier to avoid performance problems at design time than to modify them after writing the entire system, you should pay attention to the methods that control object creation in your class. In RegExpMatcher's case, if its method requires and returns a String object, it should warn of potential performance risks. Because the String class is immutable, except for the most commonly used, all String parameters need to create a new String.
Is immutability bad for performance?
Because String is often associated with a large number of object creation, it is generally attributed to its immutability. Many programmers believe that immutable objects are inherently bad for performance. But the facts are more or less complicated. In fact, immutability sometimes provides performance advantages, and mutable objects sometimes cause performance problems. Whether variability is helpful or harmful to performance, it depends on how the object is used.
Programs often process and modify text strings-they do not match immutability. Every time you want to deal with a String-you want to find and parse a prefix or substring, change lowercase or uppercase, or merge two strings-you have to create a new String object. (in the case of a merge, the compiler also creates a StringBuffer () object secretly.)
On the other hand, a reference to an immutable object can be freely shared without worrying about the referenced object being modified, which provides a performance advantage over mutable objects, as described in the next example.
Mutable objects have their own temporary object problems.
In the RegExpMatcher example, you see that when a method returns a String type, it usually needs to create a new String object. One of the problems with BadRegExpMatcher is that match () returns an object instead of an original type-but just because a method returns an object doesn't mean a new object must be created. Consider the geometry classes in java.awt, such as Point and Rectangle. A Rectangle is just a container of four integers (x, y, width, length). The AWT Component class stores the location of the component, which is returned as a Rectangle through getBounds ()
Public class Component {
...
Public Rectangle getBounds ()
}
In the above example, getBounds () is just a storage element-it only makes some state information available within some Component. Does getBounds () need to create the Rectangle it returns? It's possible. Consider the following possible implementation of getBounds ().
Public class Component {
...
Protected Rectangle myBounds
Public Rectangle getBounds () {return myBounds;}
}
When a caller calls getBounds () in the above example, no new object is created-- because the component already knows where it is-- so getBounds () is efficient. But there are other problems with the variability of Rectangle. What happens when a caller runs the program?
Rectangle r = component.getBounds ()
...
R.height * = 2
Because Rectangle is mutable, it makes Component move without Component knowing it. For GUI toolkits such as object AWT, this is a disaster because when a component moves, the screen needs to be redrawn, the listener needs to be notified, and so on. So the above code that implements Component.getBounds () looks dangerous. A more secure implementation looks like this:
Public Rectangle getBounds () {
Return new Rectangle (myBounds.x, myBounds.y
MyBounds.height, myBounds.width)
}
But now, every call to getBounds () creates a new object, just like RegExpMatcher. In fact, the following code snippet creates four temporary objects:
Int x = component.getBounds () .x
Int y = component.getBounds () .y
Int h = component.getBounds () .height
Int w = component.getBounds () .width
In the case of String, object creation is necessary because String is immutable. But in this case, object creation is also necessary because Rectangle is mutable. We use String to avoid this problem and do not use objects in our interface. Although good in the case of RegExpMatcher, this approach is not always feasible or desirable. Fortunately, you can use some techniques in the actual class to avoid the problem of too many small objects instead of avoiding them completely.
Tips for reducing objects 1: add good access functions
In the initial version of the Swing toolkit, temporary creation of small object objects, such as Point, Rectangle, and Dimension, greatly hindered performance. It seems more efficient to return more than one value at a time in a Point or Rectangle. In fact, object creation is more expensive than multiple method calls. Before the final release of Swing, the problem was simply solved by adding some new access methods to Component and other classes, such as the following:
Public int getX () {return myBounds.x;}
Public int getY () {return myBounds.y;}
Public int getHeight () {return myBounds.height;}
Public int getWidth () {return myBounds.width;}
Now a caller can get the boundary like this without creating an object:
Int x = component.getX ()
Int y = component.getY ()
Int h = component.getHeight ()
Int w = component.getWidth ()
The old form of getBounds () is still supported; good access methods simply provide effective methods to achieve the same purpose. As a result, the interfaces of Rectangle are all used in Component. When modifying the Swing package to support and use such access functions, it is twice as fast in many Swing operations. This is good because GUI code pays great attention to performance-users wait for something to happen and want the UI operation to be completed instantly.
The downside of using this technology is that your object provides more methods, and there is more than one way to get the same information, which makes the document larger and more complex, which may frighten users. But as the Swing example shows, such optimization techniques are effective when performance is concerned.
Tip 2: take advantage of variability
In addition to adding the original type of storage function to Component-- like the getX () function discussed above-- Java 2 also uses another technique in AWT and Swing to reduce object creation, allowing a caller to get the boundary as a Rectangle, but does not require any temporary object creation.
Public Rectangle getBounds (Rectangle returnVal) {
ReturnVal.x = myBounds.x
ReturnVal.y = myBounds.y
ReturnVal.height = myBounds.height
ReturnVal.width = myBounds.width
Return returnVal
}
The caller still needs to create a Rectangle object, but it can be reused in later calls. If a caller loops through a series of Component, only one Rectangle object can be created and reused in each Component. Note that this technique is only used for mutable objects; you cannot eliminate String creation in this way.
Tip 3: get the best of the two.
A better way to solve the problem of creating objects in simple classes (such as Point) is to make Point objects unavailable? But define a mutable subclass, like this:
Public class Point {
Protected int x, y
Public Point (int x, int y) {this.x = x; this.y = y;}
Public final int getX () {return x;}
Public final int getY () {return y;}
}
Public class MutablePoint extends Point {
Public final void setX (int x) {this.x = x;}
Public final void setY (int y) {this.y = y;}
}
Public class Shape {
Private MutablePoint myLocation
Public Shape (int x, int y) {myLocation = new MutablePoint (x, y);}
Public Point getLocation () {return (Point) myLocation;}
}
In the above example, Shape can safely return a reference to myLocation because the caller fails to modify the domain or call the setting function. (of course, callers can still convert Point to MutablePoint, but this is obviously not safe, and such callers may get what they want.) C++ programmers may have noticed that this technique is very similar to the constant cong Rectangle& that returns a Rectangle in C++-a feature that Java does not support.
This technique-- returning a class that is mutable and immutable, allowing only objects to be read, but not creating new objects-- is used in the java.math.BigInteger class of the Java 1.3 class library. The MutableBigInteger class is not visible-it is a private type used only internally in the java.math class library. But since some of BigInteger's methods (like gcd ()) are available in many mathematical operations, operating in one place is much better than creating hundreds of temporary variables.
Conclusion
Of all the performance optimization recommendations, it is worth remembering that there are many situations where the performance of programs is fully acceptable. In these cases, it is not worth sacrificing readability, maintainability, abstraction, or other desirable program properties for performance. However, since the seeds of many performance problems are planted at design time, be aware of the potential impact of design ideas on performance? When you design classes that focus on performance for sexual use, you can effectively use the techniques mentioned here to reduce the creation of temporary objects
In part 3, I'll look at performance problems specific to distributed applications and how to identify and eliminate them at design time.
Part III: remote interface
Overview
Many of Java's common performance problems stem from class design ideas early in the design process, long before developers start to think about performance issues. In this series, Brian Goetz discusses some of the usual Java performance adventures and explains how to avoid them at design time. In this article, it examines specific performance issues in remote applications.
The concept of remote call
In a distributed application, an object running in one system can call a method of an object in another system. This is achieved through a lot of help in making remote objects appear as local structures. To access a remote object, you first need to find it, which can be done by using a directory or naming service, such as RMI registration, JNDI, or CORBA naming service.
When you get a reference to a remote object through a directory service, you don't get an actual reference to that object, but a reference to a stub object that implements the same interface as the remote object. When you call a method of a stub object, the object aggregates all the parameters of the method-- converting them into a representation of a byte stream, similar to the serialization process. This stub object passes the collected parameters to a skeleton object over the network, decomposing the parameters into the actual object methods you want to call. This method then returns a value to the skeleton object, which the skeleton object passes to the stub object, and the stub object decomposes it and passes it to the caller. Phew! A single call has so much work to do. Obviously, despite the apparent similarity, a remote method call is larger than a local method call.
The above description browses through some details that are important to the performance of the program. When a remote method returns not an original class? What happens when it's an object? Not necessarily。 If the returned object is a type that supports remote method calls, it creates a medium stub object and a skeleton object, in which case you need to find a remote rhyme in the registry, which is obviously a costly operation. Remote objects support a distributed form of garbage collection, including that each participating JVM maintains a thread to communicate with other JVM maintenance threads and pass reference information back and forth. If the returned object does not support remote calls, all the fields and referenced objects of the object should be collected, which is also a costly operation.
Performance comparison between remote and local method calls
The performance characteristics of remote object access are different from local ones: remote object creation is more expensive than local object creation. Not only to create it when it does not exist, but also to create stub pairs and skeleton objects, and to be aware of each other.
Remote method calls also include network delivery-the aggregated parameters must be sent to the remote system, and the responses need to be pooled and sent back before the caller regains control. The delays caused by aggregation, decomposition, network latency, and actual remote calls all add up; the client usually waits for all of these steps to complete. A remote call also depends heavily on the latency of the underlying network.
Different data types have different pooling expenses. Pooling primitive types is relatively less expensive; aggregating simple objects, Point or String, is much more; aggregating remote objects is much more; and aggregating objects that reference a lot of objects (such as collection, etc.) is more. This is completely contradictory to local calls, because passing a reference to a simple object is more expensive than a reference to a complex object.
Interface design is the key.
A poorly designed remote interface may completely eliminate the performance of a program. Unfortunately, the properties of interfaces that are good for local objects may not be suitable for remote objects. A large number of temporary object creation, as discussed in the first and second parts of this series, can also hinder distributed applications, but mass delivery is a performance problem. Therefore, it may be more efficient to call a method that returns multiple values in a time object (such as a Point) than to call them multiple times to get them separately.
Some important performance guidelines for actual remote applications:
Beware of unnecessary data transmission. If an object wants to get several related items at the same time, it may be easier to implement it in a remote call if possible.
Beware of returning remote objects when the caller may not need to keep a reference to a remote object. Beware of passing complex objects when a remote object does not need a copy of the object.
Fortunately, you can find all the problems by simply looking at the interface of the remote object. The sequence of method calls that require any high-level action can be clearly seen in the class interface. If you see that a normal high-level operation requires many consecutive remote method calls, this is a warning signal, and you may need to re-examine the class interface.
Techniques for reducing the cost of remote calls
As an example, consider the following hypothetical application that manages an organizational directory: a remote Directory object contains a reference to the DirectoryEntry object, representing the entry to the phone book.
Public interface Directory extends Remote {
DirectoryEntry [] getEntries ()
Void addEntry (DirectoryEntry entry)
Void removeEntry (DirectoryEntry entry)
}
Public interface DirectoryEntry extends Remote {
String getName ()
String getPhoneNumber ()
String getEmailAddress ()
}
Now suppose you want to use Directory in a GUI email program. The program first calls getEntries () to get the list of entries, and then calls getName () in each entry to calculate the list of results. when the user selects one, the application calls getEmailAdress () at the corresponding entry to get the email address.
How many remote method calls must occur before you can write an email? You must call getEntries () once, getName () once for each entry in the address book, and getEmailAddress () once. So if there are N entries in the address, you must make N + 2 remote calls. Note that you also need to create N + 1 remote object references, which is also an expensive operation. If your address book has many entries, it is not only very slow to open the email window, but also causes network congestion, high load on your directory service, and scalability problems.
Now consider the enhanced Directory interface:
Public interface Directory extends Remote {
String [] getNames ()
DirectoryEntry [] getEntries ()
DirectoryEntry getEntryByName (String name)
Void addEntry (DirectoryEntry entry)
Void removeEntry (DirectoryEntry entry)
}
How much will this reduce the cost of your email program? Now you can call Directory.getNames () once to get all the names at the same time, just call getEntryByName () to the container you want to send email. This process requires three remote method calls instead of N + 2 and two remote objects instead of N + 1. If the address book had more names, this call reduction would vary greatly in program response and network load and system load.
The technique used to reduce the cost of remote calls and reference delivery is called the use of secondary object identifiers. Use the standard property of an object-- in this case, name-- instead of returning a remote object as a lightweight fight for the object? The secondary identifier contains enough information about the object it describes so that you only need to get the remote object you actually need. In the example of this directory system, a person's name is a good secondary identifier. In another example, a secure bag management system, a purchase identification number may be a good secondary identifier.
Another technique to reduce the number of remote calls is block acquisition. You can further add a method to the Directory interface to get more than one DirectoryEntry object at a time:
Public interface Directory extends Remote {
String [] getNames ()
DirectoryEntry [] getEntries ()
DirectoryEntry getEntryByName (String name)
DirectoryEntry [] getEntriesByName (String names [])
Void addEntry (DirectoryEntry entry)
Void removeEntry (DirectoryEntry entry)
}
Now you can not only get the remote DirectoryEntry you need, but also get all the entries you want with a single remote method call. Although this does not reduce the cost of pooling, it greatly reduces the number of network round trips. If network latency is important, you can produce a more responsive system (and reduce the use of the network).
The third trick to illuminate the path to the RMI hierarchy is not to treat DirectoryEntry as a remote object, but to define it as a common object with access functions that access name, address, email address, and other domains. In a CORBA system, I may want to use a similar object-by-value mechanism. Then, when the email application calls getEntryName (), it gets the value of an entry object-- there is no need to create a stub object or skeleton object, and the call to getEmailAddress () is also a local call rather than a remote call.
Of course, all of these techniques depend on an understanding of how remote objects are actually used, but for this understanding, you don't even need to look at the implementation of remote classes to identify some potentially serious performance problems.
The above is all the content of the article "sample Analysis designed for JAVA performance". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.