| --- |
| title: Advanced Features |
| sidebar_position: 16 |
| id: advanced_features |
| license: | |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --- |
| |
| This page covers advanced Java Fory features that are not part of first-use serialization. |
| Java native-mode zero-copy serialization is documented in [Native Serialization](native-serialization.md), and deep |
| copy semantics are documented in [Object Copy](object-copy.md). |
| |
| ## Memory Allocation Customization |
| |
| Fory provides a `MemoryAllocator` interface that allows you to customize how memory buffers are allocated and grown during serialization operations. This can be useful for performance optimization, memory pooling, or debugging memory usage. |
| |
| ### MemoryAllocator Interface |
| |
| The `MemoryAllocator` interface defines two key methods: |
| |
| ```java |
| public interface MemoryAllocator { |
| /** |
| * Allocates a new MemoryBuffer with the specified initial capacity. |
| */ |
| MemoryBuffer allocate(int initialCapacity); |
| |
| /** |
| * Grows an existing buffer to accommodate the new capacity. |
| * The implementation must grow the buffer in-place by modifying |
| * the existing buffer instance. |
| */ |
| void grow(MemoryBuffer buffer, int newCapacity); |
| } |
| ``` |
| |
| ### Using Custom Memory Allocators |
| |
| You can set a global memory allocator that will be used by all `MemoryBuffer` instances: |
| |
| ```java |
| // Create a custom allocator |
| MemoryAllocator customAllocator = new MemoryAllocator() { |
| @Override |
| public MemoryBuffer allocate(int initialCapacity) { |
| // Add extra capacity for debugging or pooling |
| return MemoryBuffer.fromByteArray(new byte[initialCapacity + 100]); |
| } |
| |
| @Override |
| public void grow(MemoryBuffer buffer, int newCapacity) { |
| if (newCapacity <= buffer.size()) { |
| return; |
| } |
| |
| // Custom growth strategy - add 100% extra capacity |
| int newSize = (int) (newCapacity * 2); |
| byte[] data = new byte[newSize]; |
| buffer.get(0, data, 0, buffer.size()); |
| buffer.initHeapBuffer(data, 0, data.length); |
| } |
| }; |
| |
| // Set the custom allocator globally |
| MemoryBuffer.setGlobalAllocator(customAllocator); |
| |
| // All subsequent MemoryBuffer allocations will use your custom allocator |
| Fory fory = Fory.builder().withXlang(false).build(); |
| byte[] bytes = fory.serialize(someObject); // Uses custom allocator |
| ``` |
| |
| ### Default Memory Allocator Behavior |
| |
| The default allocator uses the following growth strategy: |
| |
| - For buffers smaller than `BUFFER_GROW_STEP_THRESHOLD` (100MB): multiply capacity by 2 |
| - For larger buffers: multiply capacity by 1.5 (capped at `Integer.MAX_VALUE - 8`) |
| |
| This provides a balance between avoiding frequent reallocations and preventing excessive memory usage. |
| |
| ### Use Cases |
| |
| Custom memory allocators are useful for: |
| |
| - **Memory Pooling**: Reuse allocated buffers to reduce GC pressure |
| - **Performance Tuning**: Use different growth strategies based on your workload |
| - **Debugging**: Add logging or tracking to monitor memory usage |
| - **Off-heap Memory**: Integrate with off-heap memory management systems |
| |
| ## Logging |
| |
| ### ForyLogger |
| |
| By default, Fory uses a custom logger `ForyLogger` for internal needs at `WARN` level, or `INFO` level when `ENABLE_FORY_DEBUG_OUTPUT=1` is set. Set `FORY_LOG_LEVEL` to `ERROR`, `WARN`, `INFO`, or `DEBUG` to configure the process default level before startup. `ForyLogger` builds resulting logged data into a single string and sends it directly to `System.out`. The result line layout is similar to (in Log4j notation): |
| |
| ``` |
| %d{yyyy-MM-dd hh:mm:ss} %p %C:%L [%t] - %m%n |
| ``` |
| |
| The layout can't be changed. |
| |
| Example output: |
| |
| ``` |
| 2025-11-07 08:49:59 INFO CompileUnit:55 [main] - Generate code for org.apache.fory.builder.SerializedLambdaForyCodec_0 took 35 ms. |
| 2025-11-07 08:50:00 INFO JaninoUtils:121 [main] - Compile [SerializedLambdaForyCodec_0] take 144 ms |
| ``` |
| |
| ### Slf4jLogger |
| |
| If a more sophisticated logger is required, configure Fory to use Slf4j via `LoggerFactory.useSlf4jLogging()`. For example, enabling Slf4j before creating Fory: |
| |
| ```java |
| public static final ThreadSafeFory FORY; |
| |
| static { |
| LoggerFactory.useSlf4jLogging(true); |
| FORY = Fory.builder().withXlang(false) |
| .buildThreadSafeFory(); |
| } |
| ``` |
| |
| **Note:** Enabling Slf4j via `useSlf4jLogging` will be ignored when the application runs in a GraalVM native image. |
| |
| ### Suppress Fory Logs |
| |
| Both `ForyLogger` and `Slf4jLogger` allow controlling log output level or suppressing logs entirely. Configure logger level via `LoggerFactory.setLogLevel()`: |
| |
| ```java |
| static { |
| // to log only WARN and higher |
| LoggerFactory.setLogLevel(LogLevel.WARN_LEVEL); |
| |
| // to disable logging entirely |
| LoggerFactory.disableLogging(); |
| } |
| ``` |
| |
| **Note:** Selected logging level is applied before Slf4j implementation's logger level. So if you set `WARN_LEVEL` (as in the example above) then you will not see INFO messages from Fory even if INFO is enabled in Logback. |
| |
| ## Related Topics |
| |
| - [Compression](compression.md) - Data compression options |
| - [Configuration](configuration.md) - All ForyBuilder options |
| - [Native Serialization](native-serialization.md) - Java-only serialization, JDK hooks, and zero-copy buffers |
| - [Object Copy](object-copy.md) - Deep copy functionality |
| - [Xlang Serialization](xlang-serialization.md) - Java xlang interoperability |