Currently, this class uses a StringBuilder internally to manage text updates. While this is efficient for constructing strings, TextNode is not as efficient at handling strings that are not being modified: TextNode#getText() calls toString() on the internal StringBuilder, which generates a new String instance each time it is called. Since paint operations (which call getText()) are likely to occur more often than changes to the text, this is most likely producing a number of unnecessary heap allocations.
TextInput was recently updated to use a StringBuilder to construct new Strings when changes are made, but it uses a String instance internally to store the text property value. A similar approach could be taken in TextNode.